2017-07-19 4 views
7

J'emballe un fichier JAR d'application JAX-RS existant avec une application Spring Boot en utilisant cxf.jaxrs.classes-scan and cxf.jaxrs.classes-scan-packages. Lorsque je cours en tant que JAR ou avec maven spring-boot:run, l'injection de dépendance fonctionne correctement. Lorsque je cours en tant que WAR (sur WebSphere Liberty 17.0.0.2), les champs @Inject -able sont null pendant les requêtes REST.Spring Boot L'injection de dépendances JAX-RS/CXF fonctionne en JAR mais pas WAR

Voici le 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); 
    } 
} 

est ici src/main/resources/application.properties:

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

Voici le Maven pom.xml (l'application vanille JAX-RS JAR est customerservice-java qui est dans le référentiel local):

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

Voici la service Web dans le projet 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(); 
    } 
} 

Voici la fève:

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

est ici la sortie de journalisation 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/

Si je permets logging.level.org.springframework.beans.factory.support=TRACE à application.properties, je vois l'injection de dépendance fonctionnant pendant le démarrage de l'application:

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' 

Cependant, quand je fais des demandes de repos, je peux voir qu'une nouvelle instance de CustomerServiceRest est créé sur chaque demande (System.out.println dans le constructeur) et les dépendances @Inject -ables sont null (resuting dans un NullPointerException). Donc je pensais que peut-être ajouter @Singleton à CustomerServiceRest fonctionnerait, mais un nouvel objet est toujours créé sur chaque demande.

Est-ce que quelqu'un sait comment utiliser un seul bean de service Web ou pour s'assurer que Spring injecte toutes les dépendances? L'application JAR JAX-RS à la vanille JAR ne peut pas prendre en charge les dépendances de Spring.

Répondre

4

j'ai pu résoudre ce problème en ne pas utiliser CXF Liberty (en utilisant par exemple servlet & jsp caractéristiques au lieu de la fonction webProfile [qui apporte fonction de la Liberté jaxrs]), et en ajoutant exclude = { DispatcherServletAutoConfiguration.class } à l'annotation @SpringBootApplication. Ceci est seulement nécessaire pour mon type de cas d'utilisation (par ex.microservices) où DispatcherServlet est monté en tant que servlet par défaut sur / et le CXFServlet est monté avec cxf.path=/ (créant ainsi un mappage d'URL /*). Pour les autres cas où Spring MVC est mélangé avec CXF mais que les services CXF sont à un mappage d'URL non racine, le exclude n'est pas nécessaire. J'étudie toujours comment faire fonctionner ceci avec CXF de Liberty et je mettrai à jour cette réponse si je découvre.

+0

Il semble que sur Liberty, cela fonctionne si vous supprimez des fichiers JAR CXF empaquetés dans l'application à partir de WEB-INF/lib qui causaient certains conflits. – kgibm

4

Ce genre de question a eu lieu dans l'un des projets de printemps Cependant, nous avons utilisé le @Qualifier (« nom ») sur la déclaration de classe et le même qualification a été utilisé lors du câblage automatique avec la @Inject

+0

J'ai essayé de fournir un nom de chaîne '@ Named', et j'ai également essayé séparément de créer un' @ Qualifier' personnalisé et l'ai ajouté à '@ Inject', mais aucun n'a fonctionné. – kgibm

0

J'ai déployé votre code sur Tomcat 8.5.x avec JDK 1.8 et CustomerService a été injecté avec succès.

Avez-vous une chance de tester votre guerre sous Tomcat? Au moins pour comprendre si c'est un problème sur le code ou le serveur d'applications. Parfois, les bibliothèques incorporées à l'intérieur de WebSphere/Weblogic remplacent les fichiers jar provenant de vos paquets war et des problèmes similaires se produisent.

+0

Salut, oui, ça marche sous Tomcat. Je pense que vous êtes sur quelque chose avec votre dernière phrase que j'ai réalisé que j'utilisais la fonctionnalité 'webProfile-7.0' dans WebSphere et que cela apportait la fonctionnalité' jaxrs-2.0'. J'essaie maintenant avec juste 'servlet-3.1' et' jsp-2.3' et maintenant je rencontre quelques problèmes 404 apparemment parce que 'dispatcherServlet' gère la requête au lieu de' CXFServlet'. Toujours en cours d'analyse ... – kgibm

+0

Bonjour, avez-vous besoin de configurer cxf à partir de application.properties? J'ai réussi à le faire fonctionner sous WS Liberty en configurant cxf dans CustomerServiceApplication. Voir Configuration manuelle dans le guide [cxf spring boot] (http://cxf.apache.org/docs/springboot.html). – taner

+0

La configuration manuelle fonctionnerait probablement, mais je pense que cela va un peu à l'encontre de l'esprit de Spring Boot qui consiste à créer une configuration facile basée sur des annotations. Je suis sur le point de poster une autre réponse sur comment je l'ai fait fonctionner ... – kgibm