2017-07-28 6 views
1

Wenn Apache's CXF JAX-RS Spring Boot starter mit den CXF CDI dependency (cxf-integration-cdi) mit, Frühling reißen versucht, die autowiring zu tun, weil es nur JSR 330 und not CDI unterstützt. Gibt es eine Möglichkeit, CDI mit Spring Boot zu arbeiten?Frühling Stiefel mit Apache CXF und CDI

Code:

package com.ibm.test.webservices; 

import javax.enterprise.inject.Any; 
import javax.enterprise.inject.Default; 
import javax.enterprise.inject.Instance; 
import javax.inject.Inject; 
import javax.inject.Named; 
import javax.ws.rs.ApplicationPath; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 
import javax.ws.rs.core.Application; 

import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 

@SpringBootApplication 
@ApplicationPath("/") 
@Path("/") 
public class TestWebServices extends Application { 
    public static void main(String[] args) { 
     SpringApplication.run(
      TestWebServices.class, 
      "--cxf.path=/", 
      "--cxf.jaxrs.classes-scan=true", 
      "--cxf.jaxrs.classes-scan-packages=" + 
       TestWebServices.class.getPackage().getName() 
     ); 
    } 

    @Inject 
    @Any 
    private Instance<InvokerInterface> impl; 

    @GET 
    @Produces("text/plain") 
    @Path("/") 
    public String helloWorld() { 
     return impl.get().invoke(); 
    } 

    public interface InvokerInterface { 
     String invoke(); 
    } 

    @Named 
    @Default 
    public static class Implementation1 implements InvokerInterface { 
     public String invoke() { 
      return "Hello World 1\n"; 
     } 
    } 

    @Named 
    public static class Implementation2 implements InvokerInterface { 
     public String invoke() { 
      return "Hello World 2\n"; 
     } 
    } 
} 

pom.xml:

<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/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.ibm.test</groupId> 
    <artifactId>test-spring-boot-with-cdi</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <name>Test Spring Boot with Apache CXF and CDI</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> 

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.5.6.RELEASE</version> 
    </parent> 
    <dependencies> 
     <dependency> 
      <groupId>org.apache.cxf</groupId> 
      <artifactId>cxf-spring-boot-starter-jaxrs</artifactId> 
      <version>3.2.0-SNAPSHOT</version> 
     </dependency> 
     <dependency> 
      <groupId>javax.inject</groupId> 
      <artifactId>javax.inject</artifactId> 
      <version>1</version> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.cxf</groupId> 
      <artifactId>cxf-integration-cdi</artifactId> 
      <version>3.1.11</version> 
     </dependency> 
    </dependencies> 

    <!-- Required for a standalone JAR: --> 
    <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> 

Ausnahme:

2017-07-28 16:32:59.527 ERROR 9630 --- [   main] o.s.b.d.LoggingFailureAnalysisReporter : 

*************************** 
APPLICATION FAILED TO START 
*************************** 

Description: 

Field impl in com.ibm.test.webservices.TestWebServices required a bean of type 'javax.enterprise.inject.Instance' that could not be found. 


Action: 

Consider defining a bean of type 'javax.enterprise.inject.Instance' in your configuration. 

[WARNING] 
java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:90) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55) 
    at java.lang.reflect.Method.invoke(Method.java:508) 
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:527) 
    at java.lang.Thread.run(Thread.java:785) 
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testWebServices': Unsatisfied dependency expressed through field 'impl'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.enterprise.inject.Instance<com.ibm.test.webservices.TestWebServices$InvokerInterface>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject(), @javax.enterprise.inject.Any()} 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) 
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) 
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) 
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) 
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) 
    at com.ibm.test.webservices.TestWebServices.main(TestWebServices.java:22) 
    ... 6 more 
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.enterprise.inject.Instance<com.ibm.test.webservices.TestWebServices$InvokerInterface>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@javax.inject.Inject(), @javax.enterprise.inject.Any()} 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) 
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) 
    ... 25 more 
+1

Frühling nicht CDI ist. Spring implementiert CDI nicht. Wenn Sie nach leichteren Java EE-Frameworks suchen, gibt es [Hammock] (https://github.com/hammock-project/hammock) und [Wildfly Swarm] (http://wildflys-swarm.io/) –

Antwort

1

Die Schlüsselerkenntnis ist, dass Feder-Autowiring (z. B. scanBasePackages auf @SpringBootApplication, @ComponentScan usw.) vermieden werden muss. Folgende gearbeitet:

TestSpringBootApplication.java:

package com.test.webservices; 

import org.apache.cxf.cdi.CXFCdiServlet; 
import org.jboss.weld.environment.se.Weld; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.web.servlet.ServletComponentScan; 
import org.springframework.boot.web.servlet.ServletRegistrationBean; 
import org.springframework.boot.web.support.SpringBootServletInitializer; 
import org.springframework.context.ApplicationContextInitializer; 
import org.springframework.context.ConfigurableApplicationContext; 
import org.springframework.context.annotation.Bean; 

@SpringBootApplication 
// @ServletComponentScan only occurs with an embedded web server, and this is 
// needed for Tomcat: 
// https://docs.jboss.org/weld/reference/latest/en-US/html/environments.html#_tomcat 
@ServletComponentScan(basePackageClasses = { org.jboss.weld.environment.servlet.Listener.class }) 
public class TestSpringBootApplication extends SpringBootServletInitializer { 

    public static void main(String[] args) { 
     SpringApplication app = new SpringApplication(TestSpringBootApplication.class); 
     app.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() { 
      @Override 
      public void initialize(ConfigurableApplicationContext applicationContext) { 
       new Weld().initialize(); 
      } 
     }); 
     app.run(args); 
    } 

    @Bean 
    public ServletRegistrationBean cxfServletRegistration() { 
     // http://cxf.apache.org/docs/using-cxf-and-cdi-11-jsr-346.html 
     ServletRegistrationBean registration = new ServletRegistrationBean(new CXFCdiServlet(), "/*"); 
     registration.setLoadOnStartup(1); 
     return registration; 
    } 
} 

TestWebServicesApplication.java:

package com.test.webservices; 

import javax.ws.rs.ApplicationPath; 
import javax.ws.rs.core.Application; 

@ApplicationPath("/") 
public class TestWebServicesApplication extends Application { 
} 

TestWebServices.java:

package com.test.webservices; 

import javax.enterprise.inject.Any; 
import javax.enterprise.inject.Instance; 
import javax.enterprise.inject.Vetoed; 
import javax.inject.Inject; 
import javax.ws.rs.GET; 
import javax.ws.rs.Path; 
import javax.ws.rs.Produces; 

@Path("/") 
public class TestWebServices { 
    @Inject 
    @Any 
    private Instance<InvokerInterface> impl; 

    @GET 
    @Produces("text/plain") 
    @Path("/") 
    public String helloWorld() { 
     return impl.get().invoke(); 
    } 

    public interface InvokerInterface { 
     String invoke(); 
    } 

    public static class Implementation1 implements InvokerInterface { 
     public String invoke() { 
      return "Hello World 1\n"; 
     } 
    } 

    @Vetoed 
    public static class Implementation2 implements InvokerInterface { 
     public String invoke() { 
      return "Hello World 2\n"; 
     } 
    } 
} 

pom.xml:

<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/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.test</groupId> 
    <artifactId>test-spring-boot-with-cdi</artifactId> 
    <version>1.0-SNAPSHOT</version> 
    <packaging>war</packaging> 

    <name>Test Spring Boot with Apache CXF and CDI</name> 

    <properties> 
     <maven.compiler.source>1.8</maven.compiler.source> 
     <maven.compiler.target>1.8</maven.compiler.target> 
    </properties> 

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

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.5.6.RELEASE</version> 
    </parent> 
    <dependencies> 
     <dependency> 
      <groupId>org.apache.cxf</groupId> 
      <artifactId>cxf-spring-boot-starter-jaxrs</artifactId> 
      <version>3.2.0-SNAPSHOT</version> 
     </dependency> 
     <dependency> 
      <groupId>javax.inject</groupId> 
      <artifactId>javax.inject</artifactId> 
      <version>1</version> 
     </dependency> 
     <dependency> 
      <groupId>org.apache.cxf</groupId> 
      <artifactId>cxf-integration-cdi</artifactId> 
      <version>3.1.11</version> 
     </dependency> 
     <dependency> 
      <groupId>org.jboss.weld.servlet</groupId> 
      <artifactId>weld-servlet</artifactId> 
      <version>2.4.4.Final</version> 
     </dependency> 
     <dependency> 
      <groupId>org.jboss.weld.se</groupId> 
      <artifactId>weld-se</artifactId> 
      <version>2.4.4.Final</version> 
     </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> 

    <!-- Required for a standalone JAR: --> 
    <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> 

src/main/resources/META-INF/beans.xml:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" 
     version="1.1" bean-discovery-mode="all"> 
</beans> 

src/main/resources/META-INF/context.xml:

<!-- Required for Tomcat: https://docs.jboss.org/weld/reference/latest/en-US/html/environments.html#_tomcat --> 
<Context> 
    <Resource name="BeanManager" auth="Container" 
     type="javax.enterprise.inject.spi.BeanManager" factory="org.jboss.weld.resources.ManagerObjectFactory" /> 
</Context> 

JAXB Zur Verwendung in Zusätzlich zu JSON, scheint es, dass CXF die JAXRSCdiResourceExtension keine @Provider s nicht finden, so habe ich auch noch ein CDI Extension die JacksonJaxbJsonProvider als AnnotatedType erzeugt (dies scheint auch zu verlangen, dass das JAX-RS Application Objekt tut nicht Überschreibung getClasses oder getSingletons und stattdessen erkennt automatisch alle @Path e):

package com.test; 

import javax.enterprise.event.Observes; 
import javax.enterprise.inject.spi.AnnotatedType; 
import javax.enterprise.inject.spi.BeanManager; 
import javax.enterprise.inject.spi.BeforeBeanDiscovery; 

import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; 

public class RegisterCDIBeans implements javax.enterprise.inject.spi.Extension { 
    public void beforeBeanDiscovery(@Observes BeforeBeanDiscovery bbd, BeanManager beanManager) { 
     final AnnotatedType<?> annotatedType = beanManager.createAnnotatedType(JacksonJaxbJsonProvider.class); 
     bbd.addAnnotatedType(annotatedType, annotatedType.toString()); 
    } 
} 

Und dann registrieren die CDI-Erweiterung in src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension:

com.test.RegisterCDIBeans 
0

benötigen Sie den bean oder @Autowiredjavax.enterprise.inject.Instance Klasse in TestWebServices zu injizieren verwenden zu erstellen. Sie können die bean in ApplicationContax.xml erstellen und @Autowired @Qualifier verwenden, um die Klasse zu injizieren.

+0

Hallo Ich verstehe nicht, was du meinst. '@ Autowired' ist ein Frühlingskonzept, aber Spring versteht CDI nicht. Die Ausnahme zeigt, dass Spring bereits versucht, es zu verkabeln, aber es versteht nicht, wie man eine CDI-Instanz macht. Ich denke, die Lösung muss wahrscheinlich irgendwie mit einbeziehen, dass Spring die Verkabelung an cxf-integration-cdi delegiert. – kgibm

Verwandte Themen