2017-07-19 19 views
7

我正在使用cxf.jaxrs.classes-scan and cxf.jaxrs.classes-scan-packages使用Spring Boot應用程序封裝現有的vanilla JAX-RS應用程序JAR。當我作爲JAR或maven spring-boot:run運行時,依賴注入工作正常。當我作爲WAR(在WebSphere Liberty 17.0.0.2上)運行時,@Inject可用字段在REST請求期間爲nullSpring JAX-RS/CXF依賴注入在JAR中工作,但不是WAR

這裏的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); 
    } 
} 

這裏的src/main/resources/application.properties

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

這裏的Maven的pom.xml(香草JAX-RS應用程序JAR是的CustomerService的Java這是在本地倉庫):

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

這裏是在JAR項目Web服務:

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

這裏的豆:

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

這裏的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/

如果我在application.properties使logging.level.org.springframework.beans.factory.support=TRACE,我看到了依賴注入在應用程序啓動過程中工作:

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' 

然而,當我做REST的請求,我可以看到的CustomerServiceRest一個新的實例上(在構造函數中System.out.println)每個請求創建和@Inject -able依賴是null(在NullPointerException resuting)。所以我認爲可能會添加@SingletonCustomerServiceRest可以工作,但是每個請求中仍然會創建一個新對象。

有誰知道如何使用單一的Web服務bean或確保Spring注入所有的依賴關係? vanilla JAX-RS應用程序JAR本身不能承擔任何Spring依賴。

回答

4

我能夠通過不使用Liberty的CXF解決這個(例如,使用servlet & jsp特徵代替webProfile特徵[其中在Liberty的jaxrs特徵帶來]),以及添加exclude = { DispatcherServletAutoConfiguration.class }@SpringBootApplication註釋。這隻適用於我的用例類型(例如,微服務),其中DispatcherServlet作爲/上的默認servlet安裝,CXFServletcxf.path=/(因此創建/* URL映射)一起安裝。對於Spring MVC與CXF混合但CXF服務處於非根URL映射的其他情況,exclude不是必需的。我仍在研究如何讓這個與Liberty CXF一起工作,如果我找到答案,我會更新這個答案。

+0

看起來,在Liberty上,如果您從WEB-INF/lib中刪除導致一些衝突的應用程序打包的CXF JAR,它就會起作用。 – kgibm

4

這種問題的發生。然而,我們已經使用了@Qualifier(「名稱」)類聲明和相同的預選賽春天項目 之一已被使用,而與@Inject

+0

我試過提供'@ Named'字符串名稱,我也單獨嘗試創建一個自定義'@ Qualifier'並將其添加到'@Inject',但都沒有工作。 – kgibm

0

自動佈線我使用JDK 1.8將代碼部署在Tomcat 8.5.x上,並且CustomerService被成功注入。

你有沒有機會在Tomcat下測試你的戰爭。至少要了解它是否是關於代碼或應用程序服務器的問題。有時WebSphere/Weblogic中的嵌入式庫正在重寫來自war包的jar,並且會出現類似的問題。

+0

嗨,是的,它可以在Tomcat下運行。我認爲,當你意識到我在WebSphere中使用'webProfile-7.0'特性並引入了'jaxrs-2.0'特性時,你會對最後一句話有所瞭解。我正在嘗試使用'servlet-3.1'和'jsp-2.3',現在我遇到了一些404問題,看起來是因爲'dispatcherServlet'正在處理請求而不是'CXFServlet'。仍在調查... – kgibm

+0

嗨,你需要從application.properties配置cxf嗎?我設法通過在CustomerServiceApplication中配置cxf來使其在WS Liberty下運行。請參見[cxf spring boot](http://cxf.apache.org/docs/springboot.html)指南中的手動配置。 – taner

+0

手動配置可能會起作用,但我覺得這有點違背了Spring Boot的精神,它使基於註釋的配置變得容易。我即將發佈另一個關於如何使其工作的答案... – kgibm