2017-07-19 65 views
7

Owijam istniejący JAR z aplikacją JAX-RS wanilii przy pomocy aplikacji Spring Boot, używając cxf.jaxrs.classes-scan and cxf.jaxrs.classes-scan-packages. Kiedy działam jako JAR lub z maven spring-boot:run, wtrysk zależności działa dobrze. Kiedy uruchamiam jako WAR (w produkcie WebSphere Liberty 17.0.0.2), pola dostępne dla @Injectnull podczas żądań REST.Spring Boot Inwazja zależności JAX-RS/CXF działa w JAR, ale nie WAR

Oto SpringBootApplication:

@SpringBootApplication(scanBasePackages = { "com.test" }) 
public class CustomerServiceApplication extends SpringBootServletInitializer { 
    public static void main(String[] args) { 
    SpringApplication.run(CustomerServiceApplication.class, args); 
    } 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
    return application.sources(CustomerServiceApplication.class); 
    } 
} 

Oto src/main/resources/application.properties:

cxf.path=/ 
cxf.jaxrs.classes-scan=true 
cxf.jaxrs.classes-scan-packages=com.test,com.fasterxml.jackson.jaxrs.json 

Oto Maven pom.xml (aplikacja JAR wanilia JAX-RS jest customerservice-java, który znajduje się w lokalnym repozytorium):

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>customerservice-springboot</groupId> 
    <artifactId>customerservice-springboot</artifactId> 
    <packaging>war</packaging> 
    <version>2.0.0-SNAPSHOT</version> 
    <name>Customer Service :: Spring Boot</name> 

    <!-- We need to use cxf-spring-boot-starter-jaxrs 3.2.0 because of https://issues.apache.org/jira/browse/CXF-7237 
     At the time of writing this code, the latest available version in Maven central 
     is 3.1.7 so we need to use the Apache snapshot repository. --> 
    <repositories> 
     <repository> 
      <id>apache.snapshots</id> 
      <name>Apache Development Snapshot Repository</name> 
      <url>https://repository.apache.org/content/repositories/snapshots/</url> 
      <releases> 
       <enabled>false</enabled> 
      </releases> 
      <snapshots> 
       <enabled>true</enabled> 
      </snapshots> 
     </repository> 
    </repositories> 

    <properties> 
     <maven.compiler.source>1.8</maven.compiler.source> 
     <maven.compiler.target>1.8</maven.compiler.target> 
    </properties> 
    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.5.4.RELEASE</version> 
    </parent> 
    <dependencies> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
      <exclusions> 
       <exclusion> 
        <groupId>org.springframework.boot</groupId> 
        <artifactId>spring-boot-starter-tomcat</artifactId> 
       </exclusion> 
      </exclusions> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.cxf</groupId> 
      <artifactId>cxf-spring-boot-starter-jaxrs</artifactId> 
      <version>3.2.0-SNAPSHOT</version> 
     </dependency> 
     <dependency> 
      <groupId>javax.servlet</groupId> 
      <artifactId>javax.servlet-api</artifactId> 
      <scope>provided</scope> 
     </dependency> 
     <dependency> 
      <groupId>javax.json</groupId> 
      <artifactId>javax.json-api</artifactId> 
      <version>1.0</version> 
     </dependency> 
     <dependency> 
      <groupId>javax.inject</groupId> 
      <artifactId>javax.inject</artifactId> 
      <version>1</version> 
     </dependency> 
     <dependency> 
      <groupId>customerservice-java</groupId> 
      <artifactId>customerservice-java</artifactId> 
      <version>2.0.0-SNAPSHOT</version> 
      <classifier>jar</classifier> 
     </dependency> 
     <dependency> 
      <groupId>com.fasterxml.jackson.jaxrs</groupId> 
      <artifactId>jackson-jaxrs-json-provider</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>org.glassfish</groupId> 
      <artifactId>javax.json</artifactId> 
      <version>1.0.4</version> 
     </dependency> 
    </dependencies> 
    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-maven-plugin</artifactId> 
       <executions> 
        <execution> 
         <goals> 
          <goal>repackage</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

Oto lista serwis internetowy w projekcie JAR:

package com.test; 
import javax.inject.Inject; 
import javax.ws.rs.CookieParam; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.PathParam; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.Response; 

@Path("/") 
public class CustomerServiceRest { 

    @Inject 
    CustomerService customerService; 

    @GET 
    @Path("/byid/{custid}") 
    @Produces("text/plain") 
    public Response getCustomer(@PathParam("custid") String customerid, @CookieParam("token") String jwtToken) { 
     return Response.ok(customerService.getCustomerId(customerid)).build(); 
    } 
} 

Oto fasola:

package com.test; 
import javax.inject.Named; 
@Named 
public class CustomerService { 
    public String getCustomerById(String username) { 
    // ... implementation .. 
    return customerDoc.toJson(); 
    } 
} 

Oto wyjście rejestrowanie War:

. ____   _   __ _ _ 
/\\/___'_ __ _ _(_)_ __ __ _ \ \ \ \ 
(()\___ | '_ | '_| | '_ \/ _` | \ \ \ \ 
\\/ ___)| |_)| | | | | || (_| | )))) 
    ' |____| .__|_| |_|_| |_\__, |//// 
=========|_|==============|___/=/_/_/_/ 
:: Spring Boot ::  (v1.5.4.RELEASE) 
INFO c.a.s.CustomerServiceApplication - Starting CustomerServiceApplication on 23fb5f5646c3 with PID 20 (/opt/ibm/wlp/usr/servers/defaultServer/apps/expanded/customerservice-springboot-2.0.0-SNAPSHOT.war/WEB-INF/classes started by root in /opt/ibm/wlp/output/defaultServer) 
INFO c.a.s.CustomerServiceApplication - No active profile set, falling back to default profiles: default 
INFO o.s.b.c.e.AnnotationConfigEmbeddedWebApplicationContext - Refreshing org.springframework.boot[email protected]67e7ebcd: startup date [Wed Jul 19 19:36:12 UTC 2017]; root of context hierarchy 
INFO o.s.b.f.x.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [META-INF/cxf/cxf.xml] 
INFO o.s.b.f.a.AutowiredAnnotationBeanPostProcessor - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring 
INFO c.i.w.w.webapp - SRVE0292I: Servlet Message - [customerservice-springboot-2.0.0-SNAPSHOT]:.Initializing Spring embedded WebApplicationContext 
INFO o.s.w.c.ContextLoader - Root WebApplicationContext: initialization completed in 3654 ms 
INFO o.s.b.w.s.ServletRegistrationBean - Mapping servlet: 'dispatcherServlet' to [/] 
INFO o.s.b.w.s.ServletRegistrationBean - Mapping servlet: 'CXFServlet' to [/*] 
INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'errorPageFilter' to: [/*] 
INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'characterEncodingFilter' to: [/*] 
INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'hiddenHttpMethodFilter' to: [/*] 
INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'httpPutFormContentFilter' to: [/*] 
INFO o.s.b.w.s.FilterRegistrationBean - Mapping filter: 'requestContextFilter' to: [/*] 
INFO o.s.w.s.m.m.a.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.boot[email protected]67e7ebcd: startup date [Wed Jul 19 19:36:12 UTC 2017]; root of context hierarchy 
INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) 
INFO o.s.w.s.m.m.a.RequestMappingHandlerMapping - Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest) 
INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 
INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 
INFO o.s.w.s.h.SimpleUrlHandlerMapping - Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler] 
INFO o.a.c.e.ServerImpl - Setting the server's publish address to be/
INFO o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup 
INFO c.a.s.CustomerServiceApplication - Started CustomerServiceApplication in 14.955 seconds (JVM running for 271.749) 
INFO o.a.c.e.S.e.o.i.l.E.i.w.j.2.0.c.0.17.cl170220170523-1818(id=171)] - Setting the server's publish address to be/

Gdybym umożliwić logging.level.org.springframework.beans.factory.support=TRACE w application.properties widzę iniekcji zależność działa podczas uruchamiania aplikacji:

DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'customerService' 
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'customerService' 
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'customerService' to allow for resolving potential circular references 
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'customerService' [...] 
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'com.test.CustomerServiceRest' 
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'customerService' 
DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'com.test.CustomerServiceRest' 

Jednak, kiedy żądań REST, widzę, że nowa instancja CustomerServiceRest jest tworzony na każde żądanie (System.out.println w konstruktorze) i @Inject -able zależności są null (resuting w NullPointerException). Pomyślałem więc, że może dodanie @Singleton do CustomerServiceRest będzie działać, ale nowy obiekt jest nadal tworzony na każde żądanie.

Czy ktoś wie, jak korzystać z pojedynczego komponentu usługi sieci Web lub upewnić się, że Spring wstrzykuje wszystkie zależności? Waniliowy JAR aplikacji JAX-RS nie może samodzielnie przyjmować żadnych zależności Spring.

Odpowiedz

4

udało mi się rozwiązać przy braku użycia Liberty CXF (na przykład za pomocą servlet & jsp możliwości zamiast funkcji webProfile [w którym występują jaxrs funkcji Liberty]) i dodanie exclude = { DispatcherServletAutoConfiguration.class } do @SpringBootApplication adnotacji. Jest to potrzebne tylko w przypadku mojego typu użycia (np.microservices), gdzie DispatcherServlet jest zamontowany jako domyślny serwlet na /, a CXFServlet jest montowany z cxf.path=/ (tworząc w ten sposób mapowanie adresów URL na /*). W innych przypadkach, gdy Spring MVC jest mieszany z CXF, ale usługi CXF są na mapowaniu adresu URL innego niż root, exclude nie jest konieczne. Wciąż zastanawiam się, jak to wykorzystać do działania CXF Liberty'ego, a ja zaktualizuję tę odpowiedź, jeśli się dowiem.

+0

Wygląda na to, że na Liberty działa po usunięciu pakietów JAR CXF z WEB-INF/lib, które powodowały pewne konflikty. – kgibm

4

Tego rodzaju problem wystąpił w jednym projekcie sprężyny Jednak Użyliśmy @Qualifier („nazwa”) w deklaracji klasy i tej samej kwalifikator został wykorzystany podczas auto okablowanie z @Inject

+0

Próbowałem dostarczać nazwę String '@Named', a także osobno próbowałem utworzyć niestandardowy' @ Qualifier' i dodałem go do '@ Inject', ale nie zadziałało. – kgibm

0

Wdrożyłem twój kod na Tomcat 8.5.x z JDK 1.8 i pomyślnie wstrzyknięto CustomerService.

Masz szansę sprawdzić swoją wojnę pod Tomcat. Przynajmniej, aby zrozumieć, jeśli chodzi o kod lub serwer aplikacji. Czasami wbudowane biblioteki wewnątrz WebSphere/Weblogic to nadpisujące słoiki pochodzące z pakietów wojennych i podobne problemy występują.

+0

Cześć, tak, działa pod Tomcat. Wydaje mi się, że przy ostatnim zdaniu masz na myśli coś, ponieważ zdałem sobie sprawę, że korzystałem z funkcji 'webProfile-7.0' w WebSphere i która wprowadzała funkcję' jaxrs-2.0'. Próbuję teraz za pomocą 'servlet-3.1' i' jsp-2.3', a teraz wydaje mi się, że 404 problemy wydają się pozornie, ponieważ 'dispatcherServlet' obsługuje żądanie zamiast' CXFServlet'. Wciąż badam ... – kgibm

+0

Witam, czy musisz skonfigurować cxf z application.properties? Udało mi się sprawić, by działało pod WS Liberty, konfigurując cxf wewnątrz CustomerServiceApplication. Zobacz Manual Configuration w przewodniku [cxf spring boot] (http://cxf.apache.org/docs/springboot.html). – taner

+0

Ręczna konfiguracja prawdopodobnie by działała, ale wydaje mi się, że to w pewien sposób pokonuje ducha Spring Boot, który polega na łatwej konfiguracji opartej na adnotacjach. Mam zamiar opublikować inną odpowiedź o tym, jak mam to działa ... – kgibm