我正在尝试设置一个自定义Spring自动配置。
自定义自动配置需要导入常规的spring配置,但仅当上下文中存在bean时。
到目前为止,一个简单的 @ConditionalOnBean
在要导入的配置上,应按照文档中的明确说明执行:
如果@configuration类被标记为@conditional,那么与该类关联的所有@bean方法、@import注解和@componentscan注解都将受这些条件的约束。
我不想设定一个 @ConditionalOnBean
在常规Spring配置上(不在自动配置模块中)
所以我创建了第二个配置类,它只用于有条件地导入我的“旧常规配置”
这是相关代码。
自定义自动配置类
package myproject.lib.autoconfigure
@Configuration
@AutoConfigureAfter(RabbitAutoConfiguration.class)
@Import(ImportSpecificConfig.class)
public class ObjectStorageFacadeAutoConfiguration {
@Bean
@ConditionalOnMissingBean(HttpClient.class)
public HttpClient httpClient() {
return HttpClient.newHttpClient();
}
//a few other beans...
}
导入程序配置:
package myproject.lib.autoconfigure
@ConditionalOnBean(ConnectionFactory.class)
@Configuration
@Import(SpecificConfig.class)
public class ImportSpecificConfig {
@Bean
public SomeBean aBean(){
return new SomeBean();
}
}
旧的常规配置(也会导入一堆东西)
package other.lib
@Configuration
@Import(CommonConfiguration.class)
@EnableConfigurationProperties(ObjectStorageRabbitQueueProperties.class)
@ComponentScan
public class SpecificConfig {
}
我的预期行为是不处理 @Import(SpecificConfig.class)
在 ImportSpecificConfig.class
当没有 ConnexionFactory
豆子出现了。它也不应该在上下文中示例化 SomeBean
豆子。
然后我写了一个测试:
class ObjectStorageFacadeAutoConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ObjectStorageFacadeAutoConfiguration.class));
@Test
void autoConfiguredCacheManagerIsInstrumented() {
this.contextRunner
.run((context) -> {
assertThat(context).hasSingleBean(HttpClient.class);
});
}
}
此测试在启动上下文时失败。认为我在上下文中缺少了一些bean,这些bean是示例化在中定义的bean所必需的。。。 SpecificConfig
包裹。
所以我的理解(我可以用debuger确认)是 @Import
中的注解 ImportSpecificConfig
即使上下文没有任何与 @ConditionalOnBean
条件。这触发了 @ComponentScan
以及 @Import
旧的常规配置中的注解,由于上下文中不存在所需的bean(这是预期的),因此测试失败。
顺便说一下 SomeBean
实际上没有像预期的那样示例化。
奇怪的是如果我用 @ConditionalOnBean
在老规矩上 SpecificConfig
在配置类中,将发生预期的行为: @Import(CommonConfiguration.class)
未激活,则上下文初始化没有任何问题。
当然,这不是一种正确的方法,因为我不想修改lib源代码。
热释光;博士;这个 @Import
在一个 @Configuration
对带注解的类进行求值,即使 @Configuration
班级有一个 @ConditionalOnBean
计算结果为假。以及这个定义中的bean @Configuration
类没有示例化,这证实了 @ConditionalOnBean
计算结果为false。似乎@componentscan才是真正的问题。我认为这不应该被评估,但它是。
这是一个简单的可复制的例子https://github.com/fdeguibert/sample
我不明白什么?这有什么诀窍吗 @ConditionalOnBean
我看不到或者这是一种不好的行为?
1条答案
按热度按时间wkftcu5l1#
经过更多的挖掘和感谢@andywilkinson,我意识到了我的错误。
@conditionalonbean是一个有效的注册bean阶段条件。所以@import忽略了它,显然@componentscan也忽略了它,因为在parse\u配置阶段需要这个注解。
因此,如果我的理解是正确的,那么在@configuration类型级别应用的@conditionalonbean实际上将由@configuration类中定义的bean使用,而不是由类本身使用。
检查它的一个好方法是用
@Conditional(FalseCondition.class)
试图定义FalseCondition
有两种方式:第一:
->生成与@conditionalonbean相同的结果:计算@import
第二:
->@import未计算。因为这个条件在解析配置阶段适用。