java - Spring无法通过配置文件选择 Autowiring 实现

标签 java spring maven inversion-of-control autowired

我正在尝试弄清楚如何使用 @Autowired 注释在 Spring 中进行模拟实现。我正在尝试通过配置文件以以下方式插入这一点:

  1. 有一个默认配置文件,在没有定义配置时运行
  2. 指定测试配置文件后,它将 Autowiring 模拟对象而不是默认实现。

在进行此设置时,我遇到了一个问题,即 Spring 似乎无法区分我的实现之间的区别。我正在使用 Tomcat/Jersey/Maven/Spring 并且我没有使用任何 xml 配置。这是相关代码的摘要(viewable on my example GitHub)。

问题:通过 mvn clean tomcat7:run 运行它并导航到“/foo/bar”会产生以下异常(下面的完整堆栈跟踪):没有定义 [dkwestbr.spring.autowired.example.IStringGetter] 类型的合格 bean:预期单个匹配 bean 但找到 2:a,b

我意识到问题是 Spring 无法区分我的两个实现,但我无法找到如何正确声明我默认需要 a,而仅在运行 mvn test 时才需要 b。

我的初始化程序:

    @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 { }
}

我的 Web 端点有问题的 @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

最佳答案

@ActiveProfiles 注释是 meant to be used for tests .

@ActiveProfiles

A class-level annotation that is used to declare which bean definition profiles should be active when loading an ApplicationContext for test classes.

关于如何设置组件扫描的profile,take a look here.基本上只需将 @ActiveProfiles 切换为 @Profile

关于java - Spring无法通过配置文件选择 Autowiring 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19322255/

相关文章:

java - 规范中是否可以使用非实体字段?

java - 将 while 循环嵌套在 do while 循环内

java - 带约束的 Spring Data MongoDB 部分索引

maven - 如何使用环境变量激活 Maven 配置文件?

scala - NetBeans + Scala + Maven

java - 在池中的 Akka actor 实例之间共享可变数据

java - 如何在自定义验证注释上插入 ConstraintValidator 消息

java - 使用 spring Autowiring 从 java 中的静态类调用非静态方法?

java - Java配置中的Spring非主要注释

bash - 当没有 mvn -s 选项时,Maven 备用 settings.xml