2013-10-11 24 views
3

我想弄清楚如何在Spring中使用@Autowired註釋做模擬實現。我試圖通過輪廓以這樣的方式來推動這樣的:春天無法挑選配置文件自動佈線實施

  1. 有,當沒有配置定義
  2. 當指定的測試配置文件,它會自動裝配模仿對象,而不是運行在默認的配置文件默認的實現。

爲了追求這個設置,我遇到了一個問題,Spring似乎無法區分我的實現。我使用的是Tomcat/Jersey/Maven/Spring,我沒有使用任何xml配置。這裏是相關代碼的運行(viewable on my example GitHub)。

問題:由mvn clean tomcat7:run運行這一點,並導航至「/富/酒吧」產生了以下異常(以下完整的堆棧跟蹤):No qualifying bean of type [dkwestbr.spring.autowired.example.IStringGetter] is defined: expected single matching bean but found 2: a,b

我意識到這個問題是Spring可以不是我的兩者之間的區別implmentations,但我很難找到如何正確聲明,我想要一個默認情況下,和B只有當運行mvn test

我的初始化:

@Override 
    public void onStartup(ServletContext context) throws ServletException { 
     AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); 
     appContext.register(AppConfig.class); 

     context.addListener(new ContextLoaderListener(appContext)); 

     /* 
     for(String profile: appContext.getEnvironment().getActiveProfiles()) { 
      System.out.println(String.format("Active profile: %s", profile)); 
     } 
     */ 

     Map<String, String> filterParameters = new HashMap<>(); 

     // set filter parameters 
     filterParameters.put("com.sun.jersey.config.property.packages", "dkwestbr.spring.autowired.example"); 
     filterParameters.put("com.sun.jersey.config.property.JSPTemplatesBasePath", "/WEB-INF/app"); 
     filterParameters.put("com.sun.jersey.config.property.WebPageContentRegex", "/(images|css|jsp)/.*"); 


     SpringServlet servlet = new SpringServlet(); 
     ServletRegistration.Dynamic servletDispatcher = context.addServlet("jersey-servlet", servlet); 
     servletDispatcher.setInitParameters(filterParameters); 
     servletDispatcher.setLoadOnStartup(1); 
     servletDispatcher.addMapping("/*"); 
    } 

我的配置:

@Configuration 
@ComponentScan(basePackages = {"dkwestbr.spring.autowired.example"}) 
public class AppConfig { 

    @Bean 
    private static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { 
     return new PropertySourcesPlaceholderConfigurer(); 
    } 

    @Configuration 
    @PropertySource("classpath:configuration.properties") 
    static class Production { } 

    @Configuration 
    @Profile("test") 
    @PropertySource("classpath:configuration.properties") 
    static class Test { } 
} 

我的網絡端點具有所討論的@Autowired變量:

@Path("/foo") 
@Component 
public class WebEndpoint { 

    @Autowired 
    private IStringGetter getTheThing; 

    @GET 
    @Path("/bar") 
    @Produces(MediaType.TEXT_HTML) 
    public String getStuff() { 
     System.out.println(getTheThing.getItGood()); 
     return String.format("<html><body>Hello - %s</body></html>", getTheThing.getItGood()); 
    } 
} 

我的第一個實現(我想這默認):

@Component 
public class A implements IStringGetter { 

    @Value("${my.property}") 
    private String configValue; 

    @Override 
    public String getItGood() { 
     return String.format("I am an A: %s", configValue); 
    } 

} 

我的第二個實施(我只運行mvn test當想要這個):

@Component 
@ActiveProfiles("test") 
public class B implements IStringGetter { 

    @Value("${my.property}") 
    private String configValue; 

    @Override 
    public String getItGood() { 
     return String.format("I am an B: %s", configValue); 
    } 
} 

完整堆棧跟蹤:

10:22:49.136 [localhost-startStop-1] ERROR org.springframework.web.context.ContextLoader - Context initialization failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webEndpoint': Injection of autowired dependencies failed; nes 
ted exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private dkwestbr.spring.autowired.example.IString 
Getter dkwestbr.spring.autowired.example.WebEndpoint.getTheThing; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionExcepti 
on: No qualifying bean of type [dkwestbr.spring.autowired.example.IStringGetter] is defined: expected single matching bean but found 2: a,b 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostPro 
cessor.java:288) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116) ~[ 
spring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) ~[s 
pring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) ~[spr 
ing-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) ~[spring-beans-3.2.4.RELEASE.jar:3 
.2.4.RELEASE] 
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) ~[spring-beans- 
3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) ~[spring-beans-3.2.4.RELEASE.jar:3.2 
.4.RELEASE] 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4 
.RELEASE] 
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628) ~[sprin 
g-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spri 
ng-context-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) ~[spring-context-3.2.4.RELEASE 
.jar:3.2.4.RELEASE] 
     at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) ~[spring-web-3.2.4.RELEASE. 
jar:3.2.4.RELEASE] 
     at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) [spring-web-3.2.4.RELEASE.jar:3.2.4.RELEAS 
E] 
     at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) [spring-web-3.2.4.RELEASE.jar:3.2 
.4.RELEASE] 
     at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797) [tomcat-embed-core-7.0.37.jar:7.0.37] 
     at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5291) [tomcat-embed-core-7.0.37.jar:7.0.37] 
     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-7.0.37.jar:7.0.37] 
     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) [tomcat-embed-core-7.0.37.jar:7.0.37] 
     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) [tomcat-embed-core-7.0.37.jar:7.0.37] 
     at java.util.concurrent.FutureTask.run(FutureTask.java:262) [?:1.7.0_40] 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [?:1.7.0_40] 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [?:1.7.0_40] 
     at java.lang.Thread.run(Thread.java:724) [?:1.7.0_40] 
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private dkwestbr.spring.autowired.example.IStringGetter 
dkwestbr.spring.autowired.example.WebEndpoint.getTheThing; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No 
qualifying bean of type [dkwestbr.spring.autowired.example.IStringGetter] is defined: expected single matching bean but found 2: a,b 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPost 
Processor.java:514) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RE 
LEASE] 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostPro 
cessor.java:285) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     ... 22 more 
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [dkwestbr.spring.autowired.example.IStringGe 
tter] is defined: expected single matching bean but found 2: a,b 
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:865) ~[spring-bea 
ns-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770) ~[spring-beans 
-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPost 
Processor.java:486) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RE 
LEASE] 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostPro 
cessor.java:285) ~[spring-beans-3.2.4.RELEASE.jar:3.2.4.RELEASE] 
     ... 22 more 
Oct 11, 2013 10:22:49 AM org.apache.catalina.core.StandardContext listenerStart 
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'webEndpoint': Injection of autowired dependencies failed; nes 
ted exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private dkwestbr.spring.autowired.example.IString 
Getter dkwestbr.spring.autowired.example.WebEndpoint.getTheThing; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionExcepti 
on: No qualifying bean of type [dkwestbr.spring.autowired.example.IStringGetter] is defined: expected single matching bean but found 2: a,b 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostPro 
cessor.java:288) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1116) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) 
     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) 
     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) 
     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) 
     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) 
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628) 
     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) 
     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) 
     at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389) 
     at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294) 
     at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) 
     at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4797) 
     at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5291) 
     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) 
     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) 
     at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
     at java.lang.Thread.run(Thread.java:724) 
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private dkwestbr.spring.autowired.example.IStringGetter 
dkwestbr.spring.autowired.example.WebEndpoint.getTheThing; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No 
qualifying bean of type [dkwestbr.spring.autowired.example.IStringGetter] is defined: expected single matching bean but found 2: a,b 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPost 
Processor.java:514) 
     at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostPro 
cessor.java:285) 
     ... 22 more 
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [dkwestbr.spring.autowired.example.IStringGe 
tter] is defined: expected single matching bean but found 2: a,b 
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:865) 
     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770) 
     at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPost 
Processor.java:486) 
     ... 24 more 

回答

3

@ActiveProfiles註釋meant to be used for tests

@ActiveProfiles

該用於聲明其bean定義加載ApplicationContext以測試 類時 型材應該是活性的類級註釋。

至於如何設置部件scaning輪廓,take a look here.基本上只是切換@ActiveProfiles@Profile

+0

這工作得到我的主要配置運行('mvn clean tomcat7:run'),但現在測試顯示相同的堆棧跟蹤,儘管有相同的註釋。所以我猜測@Profile使得這個類只在我使用測試配置文件運行時纔可用。有沒有辦法讓春天說:「A沒有配置文件,B有測試配置文件,所以選擇B,因爲測試是當前活動配置文件」? – Dave

+1

@Dave不,沒有辦法說'A'沒有配置文件。如果配置文件處於活動狀態,那麼'@ Profile'註釋用於聲明_,註冊這個bean definition_,否則跳過它。如果沒有註釋,您無法停止註冊(您可以應用「組件掃描」排除過濾器)。實現你想要的一種方法是用'Profile(「!test」)'註釋'A',在這種情況下,只有'test'不是活動的配置文件時纔會註冊。閱讀'@ Profile'的javadoc,它更詳細地解釋了所有這些。 –

+0

配置文件(「!test」)爲我做了訣竅。就像戴夫一樣,我期望Spring只是在活動配置文件上覆蓋「默認」的bean。 – Guillaume