Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 只有当另一个主bean不存在时,如何使Springbean成为主bean_Java_Spring_Spring Boot - Fatal编程技术网

Java 只有当另一个主bean不存在时,如何使Springbean成为主bean

Java 只有当另一个主bean不存在时,如何使Springbean成为主bean,java,spring,spring-boot,Java,Spring,Spring Boot,我试图创建多个实现相同接口的bean。我有一个bean,我想用作“default”@primarybean;然而,由于它充当默认值,我希望另一个bean能够使用@Primary(或类似的东西)来创建一个主bean。换句话说,这个默认值应该是。。。“@primaryFnoprimaryReadyExist”之类的东西。例如,我有: @Configuration public class DefaultCustomObjectMapperConfiguration { @Bean

我试图创建多个实现相同接口的bean。我有一个bean,我想用作“default”@primarybean;然而,由于它充当默认值,我希望另一个bean能够使用@Primary(或类似的东西)来创建一个主bean。换句话说,这个默认值应该是。。。“@primaryFnoprimaryReadyExist”之类的东西。例如,我有:

@Configuration
public class DefaultCustomObjectMapperConfiguration {

    @Bean
    @Primary
    public ICustomObjectMapper defaultCustomObjectMapper(@Value("${objectmapper.serialize.defaultFormat:JSON}") String defaultMapperFormat,
                                                         @Qualifier(DEFAULT_XML_MAPPER_KEY) ICustomObjectMapper xmlMapper,
                                                         @Qualifier(DEFAULT_JSON_MAPPER_KEY) ICustomObjectMapper jsonMapper) {
        return "XML".equals(defaultMapperFormat) ? xmlMapper : jsonMapper;
    }

    @Bean
    @Qualifier(DEFAULT_JSON_MAPPER_KEY)
    public ICustomObjectMapper defaultJSONCustomObjectMapper() {
        return new DefaultCustomObjectMapper(new ObjectMapper());
    }

    @Bean
    @Qualifier(DEFAULT_XML_MAPPER_KEY)
    public ICustomObjectMapper defaultXMLCustomObjectMapper() {
        return new DefaultCustomObjectMapper(new XmlMapper());
    }
}
我总是想创建
defaultJSONCustomObjectMapper()
bean和
defaultXMLCustomObjectMapper()
bean,但是只有在Spring上下文中没有另一个定义为@Primary的bean时,才应该创建
defaultCustomObjectMapper()
。例如,如果其他人在同一上下文中定义了此项,则不应创建(或至少不将其用作主项):

    @Primary
    @Bean
    ICustomObjectMapper anotherCustomObjectMapper() {
        return new AnotherCustomObjectMapper();
    }
我相信您可以通过调用相同的名称来覆盖bean,但我不想这样做,因为这样它需要服务来调用这个bean,以知道它必须调用bean一些特殊的东西

这可能吗?还是有比这更好的方法

编辑: 查看Spring注释,有一个
ConditionalOnSingleCandidate
。对我来说,更准确的说法是,我想要的是相反的结果,也就是说,将(annotation=Primary.class)添加到您的“default”@primarybean应该可以做到这一点。只有在同一类型的另一个主bean尚未注册时,才会注册默认主bean

@Bean
@Primary
@ConditionalOnMissingBean(annotation = Primary.class)
public ICustomObjectMapper defaultCustomObjectMapper(@Value("${objectmapper.serialize.defaultFormat:JSON}") String defaultMapperFormat,
                                                     @Qualifier(DEFAULT_XML_MAPPER_KEY) ICustomObjectMapper xmlMapper,
                                                     @Qualifier(DEFAULT_JSON_MAPPER_KEY) ICustomObjectMapper jsonMapper) {
    // ...
}
注意,根据其他bean创建的潜在顺序,您可能希望确保最后处理这个默认bean。例如,通过添加@Order(Integer.MAX_INT)

更新:Sean正确地指出,这在本例中不起作用,因为它查找任何带有主注释的bean,而不仅仅是我们类型的bean

另一种有点难看的方法是,如果没有找到其他类型的主bean,则在创建bean之后以编程方式将bean设置为primary。这可以通过实施和执行来实现。注意,使用的是bean名称,而不是限定符

@Configuration
public class DefaultCustomObjectMapperConfiguration 
    implements BeanDefinitionRegistryPostProcessor, BeanFactoryAware {

    private BeanFactory beanFactory;

    @Value("${objectmapper.serialize.defaultFormat:JSON}") 
    private String defaultMapperFormat;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // unused
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        String[] beansOfType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory) beanFactory, ICustomObjectMapper.class);

        for(String beanName : beansOfType) {
            BeanDefinition beanDef = registry.getBeanDefinition(beanName);
            if(beanDef.isPrimary()) {
                // found an existing primary bean of same type
                return;
            }
        }
        
        // note that getBeanDefinition retrieves by bean name, which is not necessarily equal to qualifier
        BeanDefinition defaultPrimaryBeanDef = 
             registry.getBeanDefinition("XML".equals(defaultMapperFormat) ? DEFAULT_XML_MAPPER_KEY : DEFAULT_JSON_MAPPER_KEY);
        defaultPrimaryBeanDef.setPrimary(true);
    }


    @Bean(DEFAULT_JSON_MAPPER_KEY)
    @Qualifier(DEFAULT_JSON_MAPPER_KEY)
    public ICustomObjectMapper defaultJSONCustomObjectMapper() {
        return new DefaultCustomObjectMapper(new ObjectMapper());
    }

    @Bean(DEFAULT_XML_MAPPER_KEY)
    @Qualifier(DEFAULT_XML_MAPPER_KEY)
    public ICustomObjectMapper defaultXMLCustomObjectMapper() {
        return new DefaultCustomObjectMapper(new XmlMapper());
    }
}   

好极了!现在就开始测试。至于@Order,我认为ConfiditionalOnMissingBean会一直等待,直到把上下文放在一起,这样它才知道这个bean是否存在?这一点很好!文档中提到,该条件只能匹配应用程序上下文迄今为止处理过的bean定义,因此我不确定在没有明确顺序的情况下如何处理优先级。我现在注意到的是,该bean从未被创建过。当我运行一个没有自己的ICustomObjectMapper bean的服务时,它应该使用defaultCustomObjectMapper作为它的主对象,但是我得到了一个错误,因为它找到了另外2个,但没有找到主对象(调试也不会命中实例化该bean的代码)我认为这里的问题是它查找所有具有主注释的bean,而不仅仅是具有主注释的icustomobjectmapper。一个解决方法(不是有效的解决方案)是将所有带有主注释的类放在上面。。。在ConditionalOnMissingBean的“ignored”元素中,以便没有其他注释