Spring用非主bean覆盖主bean

Posted

技术标签:

【中文标题】Spring用非主bean覆盖主bean【英文标题】:Spring overriding primary bean with non-primary bean 【发布时间】:2017-07-22 17:35:34 【问题描述】:

我试图在使用@Primary 的测试配置中声明的测试期间覆盖 Spring bean。一个声明在 src/main/java 路径中,另一个声明主要在 src/test/java 路径中。

但是,Spring 有意将主 bean 替换为非主 bean,我不想将其用于测试。如果我只是注释掉生产 (src/main/java) 配置 bean,它会根据需要使用测试配置中的主要测试 (src/main/test) bean。 (显然我不能每次想运行测试时都注释掉代码。)

来自日志:

o.s.b.f.s.DefaultListableBeanFactory - 用不同的定义覆盖 bean 'sqsConnectionFactory' 的 bean 定义:替换 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真; primary=true; factoryBeanName=testJmsConfiguration; factoryMethodName=sqsConnectionFactory;初始化方法名=空; destroyMethodName=(推断);在类路径资源中定义 [com/foo/configuration/TestJmsConfiguration.class]]

[根bean:类[null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真; primary=false; factoryBeanName=jmsConfiguration; factoryMethodName=sqsConnectionFactory;初始化方法名=空; destroyMethodName=(推断);在类路径资源中定义 [com/foo/configuration/JmsConfiguration.class]]

为什么 spring 要用非主 bean 替换主 bean,我如何让 Spring 使用专门标记为主 bean 的 bean?

编辑: src/main/java 配置:

@Configuration
public class JmsConfiguration 

... other bean declarations here ...

@Bean
public SQSConnectionFactory sqsConnectionFactory(Region region) throws JMSException 
    return SQSConnectionFactory.builder()
            .withRegion(region)
            .build();


测试配置:

@Configuration
public class TestJmsConfiguration 

@Bean(name="messageProducerMock")
public MessageProducer mockMessageProducer() 
    return new MessageProducerMock();


... other bean declarations here ...

@Bean
@Primary
public SQSConnectionFactory sqsConnectionFactory(@Qualifier("messageProducerMock") MessageProducer messageProducerMock) throws JMSException 
    ... returning setup mock here


带有测试的类被注释为:

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles(profiles = "test")

【问题讨论】:

请添加测试配置和有问题的测试类。 两种不同的方法创建一个同名的bean,这样就可以发生这种行为。为您的主 bean 命名:@Bean(name="nameforbean") @alfcope 这就是答案,谢谢!如果您将此作为答案提交,我将接受它为正确的。我不知道当 Spring 知道他们正在用未标记为主要的 bean 替换标记为主要的 bean 时,为什么 Spring 会允许这种行为。 我很高兴它可以工作@FiguringThisOut。你有一个带有一点解释的答案。 【参考方案1】:

@Primary只在注入点生效,因为不同的bean匹配注入的条件而发生冲突,需要做出决定。

@Primary 在 bean 初始化时不使用。由于您使用两种不同的方法来创建同一个 bean,并且您没有命名其中任何一个,Spring 认为您正在尝试覆盖它,因此可能会发生这种行为。给定名称是最简单的解决方案,但请记住,您的上下文仍将初始化您不想使用的 bean。

【讨论】:

感谢您的解决方案和解释。 更改使用@Bean 注释的冲突方法之一的方法名称 似乎也可以作为一种修复(以区分bean 定义)。【参考方案2】:

我认为您的测试课程中可能缺少@ContextConfiguration

测试配置类示例(src/test/java/TestConfiguration.class):

@Configuration
@ComponentScan
public class TestConfiguration 
    @Bean
    RabbitSender rabbitSender() 
        return mock(RabbitSender.class);
    


测试类示例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfiguration.class)
public class SomeServiceTest 


【讨论】:

当前配置正在根据需要加载主 bean,只是非主 bean 正在替换它。手动添加 @ContextConfiguration 有什么不同?我仍然需要包含替换主 bean 的 bean 的其他配置类,因为它有其他 bean 声明。 如果做这样的事情,你不需要写@Primary。 TestConfiguration 类中的 Bean 将覆盖“主要”bean。这个注解告诉 Spring 你想为特定的测试使用特定的配置,所以它会覆盖其他的。

以上是关于Spring用非主bean覆盖主bean的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2.1 bean 覆盖与 Primary

如何按名称覆盖 Spring 服务 bean,仅使用注释

Spring-Data REDIS 的 Spring Bean 覆盖

Spring Boot:@TestConfiguration 在集成测试期间不覆盖 Bean

Spring Boot:在单元测试中用一个覆盖多个bean

Spring 实现覆盖容器中Bean的注解实现 @OverrideBean