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