Spring overriding primary bean with non-primary bean

…衆ロ難τιáo~ 提交于 2019-12-06 17:06:10

问题


I am trying to override a Spring bean during a test declared in a test configuration with the use of @Primary. One declaration is in the src/main/java path, the other, the primary, is in src/test/java path.

However, Spring is intentionally replacing the primary bean with the the non-primary bean, the one I don't want to use for the test. If I simply comment out the production (src/main/java) configuration bean, it uses the primary test (src/main/test) bean in the test configuration as desired. (Clearly I can't comment out code every time I want to run a test.)

From the logs:

o.s.b.f.s.DefaultListableBeanFactory - Overriding bean definition for bean 'sqsConnectionFactory' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=true; factoryBeanName=testJmsConfiguration; factoryMethodName=sqsConnectionFactory; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/foo/configuration/TestJmsConfiguration.class]]

with

[Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jmsConfiguration; factoryMethodName=sqsConnectionFactory; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/foo/configuration/JmsConfiguration.class]]

Why is spring replacing a primary bean with a non-primary bean and how do I get Spring to use the bean specifically marked as the primary bean?

Edit: The src/main/java configuration:

@Configuration
public class JmsConfiguration {

... other bean declarations here ...

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

The test configuration:

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

The class with the tests is annotated with:

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

回答1:


@Primary takes effect only at injection point, when there is a conflict because different beans match the condition to be injected, and a decision needs to be made.

@Primary is not used at beans initialisation. As you are using two different methods creating the same bean, and you are not naming any of them Spring considers you are trying to override it, so this behaviour can happen. Given a name is the easiest solution, but bear in mind that your context will still be initialising the bean you do not want use.




回答2:


I think you might be missing @ContextConfiguration in your test class.

Example of test configuration class (src/test/java/TestConfiguration.class):

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

}

Example of test class:

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

}


来源:https://stackoverflow.com/questions/42564809/spring-overriding-primary-bean-with-non-primary-bean

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!