首页 > 解决方案 > Bean中冲突时Spring Bean创建异常

问题描述

以下是我们项目中使用的通用启动器中的代码。

@ConditionalOnProperty(prefix = "some.prefix", value = "some-enable")
@EnableConfigurationProperties(value = {
    SomeProperties.class,
})
@Configuration
class RabbitGenericValueConfiguration {

    @Autowired
    public void setuoRabbit(AmqpAdmin admin) {
        admin.declareExchange(exchange());
    }

    @ConditionalOnProperty(prefix = "existing.property", value = "setup")
    @ConditionalOnMissingBean
    @Bean
    Exchange exchange() {
        return ExchangeBuilder.topicExchange(properties.getExchange())
            .build();
    }

}    

在我们的服务中,我们需要创建一个自定义交换,但是每当我们添加以下代码时,都会发生以下错误

@Configuration
    public class CustomConfiguration {


        @Bean
        public DirectExchange direct() {
            return new DirectExchange("test.direct");
        }

    }

例外是

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'exchange' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.obtainBeanInstanceFromFactory(ConfigurationClassEnhancer.java:389)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
    at com.something.RabbitGenericValueConfiguration$$EnhancerBySpringCGLIB$$2df2c1f1.exchange(<generated>)
    at com.something.RabbitGenericValueConfiguration.setuoRabbit(RabbitGenericValueConfiguration.java:145)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

问题是为什么应用程序在自定义交换不存在时启动,而在自定义交换存在时失败。

标签: javaspringspring-bootrabbitmq

解决方案


您声明了exchange命名的 bean,例如:

@ConditionalOnProperty(prefix = "existing.property", value = "setup")
@ConditionalOnMissingBean
@Bean
Exchange exchange() {
    return ExchangeBuilder.topicExchange(properties.getExchange())
        .build();
}

听起来这两个声明的 bean 是从Exchange类派生的。因此,@ConditionalOnMissingBean如果首先实例化该 bean,则注释的存在会阻止该 bean 被实例化:

@Bean
public DirectExchange direct() {
    return new DirectExchange("test.direct");
}

正如@ConditionalOnMissingBeanjavadoc所说(重点是我的):

仅当指定的 bean 类和/或名称尚未包含在 BeanFactory中时才匹配的条件。

@ConditionalOnMissingBean如果您希望 Spring 实例化两者,您可能应该删除。


推荐阅读