Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 为什么在它应该检查的bean之前调用@ConditionalOnMissingBean?_Spring_Spring Boot_Kotlin - Fatal编程技术网

Spring 为什么在它应该检查的bean之前调用@ConditionalOnMissingBean?

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

在我的SpringBoot应用程序中,我只希望在模块未启用时创建bean

在CoreConfig中,我定义了两个bean(geocoder和travelDistanceCalculator) 用引用那些bean应该初始化的接口的
@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/in
CoreConfig

编辑


如果您想在属性丢失时使用
@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)

}