Spring 为什么在它应该检查的bean之前调用@ConditionalOnMissingBean?
在我的SpringBoot应用程序中,我只希望在模块未启用时创建bean 在CoreConfig中,我定义了两个bean(geocoder和travelDistanceCalculator) 用引用那些bean应该初始化的接口的Spring 为什么在它应该检查的bean之前调用@ConditionalOnMissingBean?,spring,spring-boot,kotlin,Spring,Spring Boot,Kotlin,在我的SpringBoot应用程序中,我只希望在模块未启用时创建bean 在CoreConfig中,我定义了两个bean(geocoder和travelDistanceCalculator) 用引用那些bean应该初始化的接口的@ConditionalOnMissingBean注释 @Configuration class CoreConfig { private val logger = loggerFor<CoreConfig>() @Bean @Co
@ConditionalOnMissingBean
注释
@Configuration
class CoreConfig {
private val logger = loggerFor<CoreConfig>()
@Bean
@ConditionalOnMissingBean(Geocoder::class)
fun geocoder(): Geocoder {
logger.warn("no Geocoder bean instance has been provided. Instantiating default.")
return object : Geocoder {
override fun getGeocode(address: String) = Coordinates.Unavailable
}
}
@Bean
@ConditionalOnMissingBean(TravelDistanceCalculator::class)
fun travelDistanceCalculator(): TravelDistanceCalculator {
logger.warn("no TravelDistanceCalculator bean instance has been provided. Instantiating default.")
return object : TravelDistanceCalculator {
override fun getTravelDistanceInKm(origin: Coordinates, destination: Coordinates) = Double.NaN
}
}
// other beans definitions...
}
app.geolocation.enable
在application.yml中定义为true
这里发生的事情是,在启动时,即使启用了GeolocationConfig,并且在此之后不久初始化了ApiceClient,在CoreConfig中定义的geocoder和travelDistanceCalculator默认bean也会被初始化
这里缺少什么?
条件缺失bean
取决于@Configuration
类的处理顺序及其bean的定义。在您的示例中,我怀疑正在处理CoreConfig
,它的条件被评估,并且它的bean在您的hereApiClient
bean被定义之前被定义。因此,当评估缺少的bean条件时,没有找到匹配的bean,并且定义了geocoder
和travelDistanceCalculator
bean
ConditionalOnMissingBean
的javadoc提出以下建议:
该条件只能匹配应用程序上下文迄今为止处理过的bean定义,因此,强烈建议仅在自动配置类上使用该条件。如果候选bean可能是由另一个自动配置创建的,请确保使用此条件的bean随后运行
您可以通过在配置类上使用@Order
来遵循此建议。或者(我认为最好是这样)您可以通过在org.springframework.boot.autoconfigure.enableautoconfigure
键下的META-INF/spring.factories
中列出CoreConfig
自动配置类,并将其移动到组件扫描无法获取的包中。@ConditionalOn(缺失)Bean
用于自动配置类。
如果在公共配置类中使用,则结果取决于首先加载的配置。见安迪·威尔金森的回答
在您的情况下,您可以轻松地使用相同的属性(您已经提供)来配置正确的bean
在GeolocationConfig
使用@ConditionalOnProperty(name=“app.geolocation.enable”,havingValue=“false”)
on/inCoreConfig
编辑
如果您想在属性丢失时使用
@CoreConfig
,请使用@conditionalnproperty(name=“app.geolocation.enable”,havingValue=“false”,matchifmessing=true)
。这两种配置在同一个jar中吗?是的,在同一个jarOk中,因此您可能可以使用@conditionalnproperty(name=“app.geolocation.enable”,havingValue=“false”)
在CoreConfig
上,我认为核心模块不应该知道任何关于地理定位模块的信息,这就是为什么我没有提到“app.geolocation.enable”,但由于属性和配置在同一个模块中,我只是想得太多了。@noiaverbale如果你真的想要核心模块,你就不应该知道任何关于地理定位模块的事情,你应该采用Andy的方法。另一方面,您“需要”一个属性来配置GeolocationConfig
。。。一个小的改进可能是在缺少该属性时使用CoreConfig
。请参阅editAuto配置类在我看来像是过度工程,但感谢您的回答
@Configuration
@ConditionalOnProperty("app.geolocation.enable")
class GeolocationConfig {
@Bean
fun hereApiClient(
geolocationProperties: GeolocationProperties,
restTemplate: RestTemplate
): HereApiClient =
HereApiClient(restTemplate, geolocationProperties)
}