2013-10-11 2 views
3

Я пытаюсь выяснить, как выполнять макет реализации весной, используя @Autowired аннотацию. Я пытаюсь управлять этими профилями таким образом, что:Весна не в состоянии выбрать Autowired реализацию по профилю

  1. Существует профиль по умолчанию, который запускается, когда конфигурация не определена
  2. Когда задан тестовый профиль, он будет Autowire фиктивных объектов вместо реализации по умолчанию.

В поисках этой установки у меня возникает проблема, когда Spring, похоже, не может отличить мои реализации. Я использую Tomcat/Jersey/Maven/Spring, и я не использую конфигурацию xml. Вот прогон соответствующего кода (viewable on my example GitHub).

Проблема: Запуск этого с помощью mvn clean tomcat7:run и навигации к «/ Foo/бар» производит следующее исключение (полный трассировки стека ниже): No qualifying bean of type [dkwestbr.spring.autowired.example.IStringGetter] is defined: expected single matching bean but found 2: a,b

Я понимаю, что проблема Spring не может различать два моих но мне трудно найти, как правильно объявить, что я хочу по умолчанию, и 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

аннотацию на уровне класса, который используется для объявления, которое боба определение профили должны быть активными при загрузке ApplicationContext для испытания классов.

А как установить профиль для компонента просмотрит, take a look here. В основном только переключатель @ActiveProfiles с @Profile.

+0

Это работало, чтобы запустить мою основную конфигурацию ('mvn clean tomcat7: run'), но теперь тест показывает одну и ту же трассировку стека, несмотря на те же аннотации. Поэтому я предполагаю, что @Profile делает класс доступным только тогда, когда я запускаю профиль Test.Есть ли способ заставить весну сказать, что «A не имеет профиля, B имеет профиль теста, поэтому выберите B, потому что тест является текущим активным профилем»? – Dave

+1

@Dave Нет никакого способа сказать, что 'A' не имеет профиля. Аннотации '@ Profile' используются для указания: если этот профиль активен, зарегистрируйте этот бит, а иначе пропустите его. Без аннотации вы не можете остановить регистрацию (вы можете применить фильтры исключения «компонент-сканирование»). Один из способов добиться того, что вы хотите, - это аннотировать «A» с помощью «Profile («! Test »)», и в этом случае он будет зарегистрирован только в том случае, если 'test' не является активным профилем. Прочтите javadoc '@ Profile', он объясняет все это более подробно. –

+0

Профиль («! Test») сделал трюк для меня. Как Дейв, я ожидал, что Spring просто переопределит бобы из активного профиля поверх «по умолчанию» ... – Guillaume

Смежные вопросы