微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

仅当另一个 Primary bean 不存在时,您如何制作一个 Spring bean Primary

如何解决仅当另一个 Primary bean 不存在时,您如何制作一个 Spring bean Primary

我正在尝试创建多个实现相同接口的 bean。我有一个 bean,我想将其用作“认”@Primary bean;但是,由于它作为认值,我希望另一个 bean 能够使用 @Primary(或类似的东西)来创建主 bean。换句话说,这个认的应该是......“@PrimaryIfnoprimaryAlreadyExist”之类的东西。例如,我有这个:

@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,但是只有在没有其他 bean 时才应该创建 defaultCustomObjectMapper()定义为@Primary 的 Spring 上下文。例如,如果其他人在同一上下文中定义了它,则不应创建(或至少不应用作主要):

    @Primary
    @Bean
    ICustomObjectMapper anotherCustomObjectMapper() {
        return new AnotherCustomObjectMapper();
    }

我相信您可以通过将 bean 命名为相同的名称来覆盖它,但我不想那样做,因为这样需要服务将它拉进来才能知道它必须调用 bean 一些特殊的东西。

这可能吗?或者有没有比这更好的方法

编辑: 查看 Spring 注释,有 ConditionalOnSingleCandidate。对我来说,我想要相反的说法会更准确,即 ConditionalOnMultipleCandidates

解决方法

@ConditionalOnMissingBean(annotation = Primary.class) 添加到您的“默认”@Primary bean 应该可以解决问题。如果尚未注册另一个相同类型的主 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 正确地指出 @ConditionalOnMissingBean 在这种情况下不起作用,因为它查找任何带有 Primary 注释的 bean,而不仅仅是我们类型的 bean。

如果没有找到该类型的其他主要 bean,则在创建 bean 后以编程方式将 bean 设置为主要 bean,这是一个有点丑陋的替代方法。这可以通过实现 BeanDefinitionRegistryPostProcessorBeanFactoryAware 来完成。请注意,使用的是 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());
    }
}   

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。