2017-07-19 2 views
7

Ich wickle eine vorhandene Vanille JAX-RS-Anwendung JAR mit einer Spring Boot-Anwendung mit cxf.jaxrs.classes-scan and cxf.jaxrs.classes-scan-packages. Wenn ich als JAR oder mit maven spring-boot:run ausgeführt werde, funktioniert die Abhängigkeitsinjektion einwandfrei. Wenn ich als WAR (unter WebSphere Liberty 17.0.0.2) ausgeführt werde, sind die Felder @Inject -able null während REST-Anforderungen.Spring Boot JAX-RS/CXF-Abhängigkeitsinjektion funktioniert in JAR, aber nicht WAR

Hier ist die 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); 
    } 
} 

Hier src/main/resources/application.properties:

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

Hier ist die Maven pom.xml (die Vanille-JAX-RS Anwendung JAR ist Kundendienst-java, die im lokalen Repository ist):

<?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> 

Hier ist die Web-Service in dem JAR-Projekt:

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(); 
    } 
} 

Hier ist die Bohne:

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

Hier ist die WAR-Protokollausgabe:

. ____   _   __ _ _ 
/\\/___'_ __ _ _(_)_ __ __ _ \ \ \ \ 
(()\___ | '_ | '_| | '_ \/ _` | \ \ \ \ 
\\/ ___)| |_)| | | | | || (_| | )))) 
    ' |____| .__|_| |_|_| |_\__, |//// 
=========|_|==============|___/=/_/_/_/ 
:: 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/

Wenn ich logging.level.org.springframework.beans.factory.support=TRACE in application.properties ermöglichen, sehe ich die Dependency Injection Arbeiten während der Anwendung Start:

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' 

Allerdings, wenn ich REST-Anfragen machen, kann ich auf jede Anfrage eine neue Instanz von CustomerServiceRest erstellt (System.out.println im Konstruktor) und die @Inject -able Abhängigkeiten sind null (resuting in einem NullPointerException) sehen, dass. Also dachte ich, dass das Hinzufügen von @Singleton zu CustomerServiceRest funktionieren würde, aber ein neues Objekt wird immer noch bei jeder Anfrage erstellt.

Kann jemand eine einzelne Webservice-Bean verwenden oder sicherstellen, dass Spring alle Abhängigkeiten eingibt? Die Vanille-JAX-RS-Anwendung JAR kann selbst keine Spring-Abhängigkeiten übernehmen.

Antwort

4

Ich konnte dies lösen, indem nicht Libertys CXF (z.B. servlet & jsp Funktionen anstelle der webProfile-Funktion [die jaxrs Funktion in Liberty bringt]) und das Hinzufügen von exclude = { DispatcherServletAutoConfiguration.class } zum @SpringBootApplication Anmerkung. Dies wird nur für meine Art von Anwendungsfall benötigt (z.B.Microservices), bei denen DispatcherServlet als Standard-Servlet unter / und CXFServlet mit cxf.path=/ gemountet ist (wodurch eine /* URL-Zuordnung erstellt wird). In anderen Fällen, in denen Spring MVC mit CXF gemischt ist, aber die CXF-Dienste eine Zuordnung ohne Root-URL aufweisen, ist exclude nicht erforderlich. Ich untersuche noch, wie man das mit Libertys CXF zum Laufen bringt und ich werde diese Antwort aktualisieren, wenn ich es herausfinden sollte.

+0

Es scheint, dass es auf Liberty funktioniert, wenn Sie App-verpackte CXF JARs aus WEB-INF/lib entfernen, die einige Konflikte verursachten. – kgibm

4

Diese Art von Problem trat in einer der Feder Projekt jedoch wir die @Qualifier („name“) auf der Klassendeklaration und der gleichen Qualifier verwendet wurde, mit der @Inject

+0

Ich habe versucht, einen '@ Named' String-Namen, und ich habe auch separat versucht, ein benutzerdefiniertes' @ Qualifier' und fügte es zu dem '@ Inject', aber keiner funktionierte. – kgibm

0

während automatische Verkabelung verwendet haben Ich habe Ihren Code auf Tomcat 8.5.x mit JDK 1.8 implementiert und CustomerService wurde erfolgreich injiziert.

Haben Sie eine Chance, Ihren Krieg unter Tomcat zu testen. Zumindest um zu verstehen, ob es sich um einen Fehler im Code oder App-Server handelt. Gelegentlich überschreiben eingebettete Bibliotheken in WebSphere/Weblogic die von Ihren Kriegspaketen kommenden Dateien, und ähnliche Probleme treten auf.

+0

Hallo, ja, es funktioniert unter Tomcat. Ich denke, dass Sie mit Ihrem letzten Satz etwas anfangen, als ich merkte, dass ich die Funktion "webProfile-7.0" in WebSphere verwendete und die 'jaxrs-2.0'-Funktion einführte. Ich versuche jetzt mit nur 'servlet-3.1' und' jsp-2.3' und jetzt treffe ich anscheinend einige 404 Probleme, weil das 'dispatcherServlet' die Anfrage statt' CXFServlet' bearbeitet. Noch zu untersuchen ... – kgibm

+0

Hallo, müssen Sie cxf von application.properties konfigurieren? Ich habe es geschafft, es unter WS Liberty arbeiten zu lassen, indem ich cxf in CustomerServiceApplication konfiguriere. Weitere Informationen finden Sie unter Manuelle Konfiguration im Handbuch [cxf spring boot] (http://cxf.apache.org/docs/springboot.html). – taner

+0

Manuelle Konfiguration würde wahrscheinlich funktionieren, aber ich fühle, dass es irgendwie den Geist von Spring Boot besiegt, der eine einfache, Annotations-basierte Konfiguration ist. Ich bin dabei, eine weitere Antwort darüber zu veröffentlichen, wie ich es zum Laufen gebracht habe ... – kgibm

Verwandte Themen