在Spring上下文中使用注解和xml配置的Bean覆盖

时间:2019-01-26 19:26:04

标签: spring spring-bean

有一个完全基于注释的spring项目A。 我需要在项目B中有条件地覆盖一些bean,该项目B是使用Spring 4.1.3的旧应用程序,并使用基于xml的配置。

有FooConfig使用@ComponentScan配置bean。此配置是我的第三方代码。即我无权访问

@ComponentScan(basePackages = {"com.foo.bean"})
@Configuration
public class FooConfig {
}

我在末端创建了一个BarConfig,它导入了FooConfig并根据条件覆盖了一些bean。这是使用@Conditional

实现的
@Configuration
@Import(FooConfig.class)
public class BarConfig {

    @Bean(name="helloService")
    @Conditional(IsSpanishCondition.class)
    public HelloService getHelloService() {
        return new HelloService() {
            @Override
            public String getGreeting(String name) {
                return "Hola "+name;
            }
        };
    }
}

我在我的application-context.xml中包含了BarConfig

    <context:annotation-config/>
    <bean class="com.foo.config.BarConfig"/>

虽然此方法在Spring 5.1.2.RELEASE中完美无缺,但在Spring 4.1.3.RELEASE中不起作用

  

00:14:20.617 [main]信息org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader-跳过[BeanMethod:name = getHelloService,declaringClass = com.foo.config.BarConfig]的bean定义:bean'helloService的定义' 已经存在。此顶级bean定义被视为替代。

此外,在完全基于注释的上下文中,我在Spring 4中也观察到了同样的问题。即不是由于xml和注释配置的混合,而是由于此处使用的Spring版本

问题
春季5发生了什么变化?
在使用同时使用xml和注释配置的Spring应用程序时,有什么经验法则吗?特别是在覆盖bean时?

也是FTR,这些都是可行的解决方案
1.使用BeanPostProcessor覆盖Bean
2.使用配置文件。但这不适用于复杂的条件。

@Profile("ENGLISH")
@Configuration
@Import(FooConfig.class)
public class EnglishConfig {
}
@Profile("SPANISH")
@Configuration
public class SpanishConfig {
    @Bean(name="helloService")
    public HelloService getHelloService() {
        return new HelloService() {
            @Override
            public String getGreeting(String name) {
                return "Hola "+name;
            }
        };
    }
}

1 个答案:

答案 0 :(得分:0)

这里的问题是,您正在尝试从@Configuration类覆盖xml bean,现在我不是100%确信,但是在春季4中,xml bean在选择bean上仍然具有优先权,因此@Configuration bean将不会获得覆盖xml bean的权限。该问题已在春季5解决。

您猜想您使用BeanPostProcessor的方法是唯一可行的解​​决方案。

我在想,也许您可​​以使用其他bean名称,实现自己的行为,并使用@Qualifier注释选择将被选中的bean?