在Spring Boot应用程序中,我希望仅在未启用模块的情况下才能创建bean。
在CoreConfig中,我定义了两个bean(地理编码器和travelDistanceCalculator)
带有@ConditionalOnMissingBean
的注释,引用了这些bean应该初始化的接口。
@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...
}
然后GeolocationConfig定义了同时实现Geocoder和TravelDistanceCalculator接口的bean(HereApiClient)。
@Configuration
@ConditionalOnProperty("app.geolocation.enable")
class GeolocationConfig {
@Bean
fun hereApiClient(
geolocationProperties: GeolocationProperties,
restTemplate: RestTemplate
): HereApiClient =
HereApiClient(restTemplate, geolocationProperties)
}
app.geolocation.enable
在application.yml中定义为true
。
这里发生的是,在启动时,即使启用了GeolocationConfig并在它们之后不久初始化了HereApiClient,也会初始化CoreConfig中定义的geocoder和travelDistanceCalculator默认bean。
我在这里想念什么?
答案 0 :(得分:2)
ConditionalOnMissingBean
取决于@Configuration
类的处理顺序和定义其bean的顺序。在您的示例中,我怀疑正在CoreConfig
Bean被处理之前,正在hereApiClient
的处理,其条件的评估以及其Bean的定义。结果,当评估缺少的bean条件时,找不到匹配的bean,并且定义了geocoder
和travelDistanceCalculator
bean。
ConditionalOnMissingBean
的Javadoc提出以下建议:
该条件只能匹配到目前为止应用程序上下文已处理的bean定义,因此,强烈建议仅在自动配置类上使用此条件。如果候选bean可能是由另一种自动配置创建的,请确保使用此条件的豆在此之后运行。
您可以通过在配置类上使用@Order
来遵循此建议。或者(我认为最好是)您可以将CoreConfig
设置为自动配置类,方法是将其列在META-INF/spring.factories
键下的org.springframework.boot.autoconfigure.EnableAutoConfiguration
中,然后将其移动到不会通过组件扫描拾取。
答案 1 :(得分:1)
@ConditionalOn(Missing)Bean
旨在用于自动配置类。 see javadoc
如果在通用配置类中使用,那么结果取决于首先加载的配置。见安迪·威尔金森答案
在您的情况下,您可以轻松地使用相同的属性(已经提供)来配置正确的bean。
在@ConditionalOnProperty(name="app.geolocation.enable")
上使用GeolocationConfig
在@ConditionalOnProperty(name="app.geolocation.enable",havingValue="false")
上/之中使用CoreConfig
编辑
如果缺少属性,则要使用@ConditionalOnProperty(name="app.geolocation.enable",havingValue="false",matchIfMissing = true)
,请使用CoreConfig
。