如何解决仅当另一个 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,这是一个有点丑陋的替代方法。这可以通过实现 BeanDefinitionRegistryPostProcessor 和 BeanFactoryAware 来完成。请注意,使用的是 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 举报,一经查实,本站将立刻删除。