Почему @ConditionalOnMissingBean вызывается перед бином, который он должен проверить? - PullRequest
0 голосов
/ 20 февраля 2019

В моем приложении Spring Boot я хочу, чтобы bean-компоненты создавались, только если модуль не включен.

В CoreConfig я определил два bean-компонента (geocoder и 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 определяет bean-компонент (HereApiClient), реализующий интерфейсы Geocoder и TravelDistanceCalculator.

@Configuration
@ConditionalOnProperty("app.geolocation.enable")
class GeolocationConfig {

    @Bean
    fun hereApiClient(
        geolocationProperties: GeolocationProperties,
        restTemplate: RestTemplate
    ): HereApiClient =
        HereApiClient(restTemplate, geolocationProperties)

}

app.geolocation.enable определяется как true в application.yml.

В данном случае происходит то, что при запуске bean-компоненты по умолчанию для геокодера и travelDistanceCalculator, определенные в CoreConfig, инициализируются, даже если включен GeolocationConfig, а вскоре после них инициализируется HereApiClient.

Чего мне здесь не хватает

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

@ConditionalOn(Missing)Bean предназначен для использования в классах автоконфигурации. см. Javadoc Если используется в общих классах конфигурации, результат зависит от того, какая конфигурация загружается первой.См. Andy-wilkinson answer

В вашем случае вы можете легко использовать то же свойство (которое вы уже предоставляете) для настройки правильных 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 использовалось, если свойствоотсутствует.

0 голосов
/ 20 февраля 2019

ConditionalOnMissingBean зависит от порядка обработки классов @Configuration и определения их бинов.В вашем примере, я подозреваю, что CoreConfig обрабатывается, его условия оцениваются, и его bean-компоненты определены до того, как ваш bean-компонент hereApiClient был определен.В результате при оценке условий отсутствующего компонента не найдено ни одного соответствующего компонента и определены компоненты geocoder и travelDistanceCalculator.

Javadoc для ConditionalOnMissingBean дает следующую рекомендацию:

Условие может соответствовать только определениям компонентов, которые до сих пор обрабатывались контекстом приложения, и поэтому настоятельно рекомендуется использовать это условие только для классов автоконфигурации.Если потенциальный бин может быть создан другой автоконфигурацией, убедитесь, что после этого выполняется тот, который использует это условие.

Вы можете следовать этой рекомендации, используя @Order в ваших классах конфигурации.В качестве альтернативы (и желательно, на мой взгляд) вы можете сделать CoreConfig классом автоконфигурации, перечислив его в META-INF/spring.factories под клавишей org.springframework.boot.autoconfigure.EnableAutoConfiguration и переместив его в пакет, где он не будет обнаружен при сканировании компонента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...