Java 只有当另一个主bean不存在时,如何使Springbean成为主bean
我试图创建多个实现相同接口的bean。我有一个bean,我想用作“default”@primarybean;然而,由于它充当默认值,我希望另一个bean能够使用@Primary(或类似的东西)来创建一个主bean。换句话说,这个默认值应该是。。。“@primaryFnoprimaryReadyExist”之类的东西。例如,我有: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
@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”元素中,以便没有其他注释