У меня есть проект Spring Boot 1.5.x
, где некоторые @Component
зависят от других @Component
, и, в конечном счете, по цепочке зависимостей некоторые @Component
могут быть включены или полностью отключены с помощью @ConditionalOnProperty
.
Я использую @ConditionalOnBean
, чтобы избежать создания экземпляра @Component
, который зависит от других @Component
, которые не были созданы из-за отсутствия properties
.
Однако он работает только для прямых зависимостей, а не для транзитивных зависимостей, но я не могу понять, почему.
Позвольте мне попытаться объяснить на простом примере.
Учитывая MyServices.kt
:
private val logger = KotlinLogging.logger {}
class MyServices
@ConditionalOnProperty("service.a")
@Service
class ServiceA {
init {
logger.info { "A SERVICE" }
}
}
@ConditionalOnBean(ServiceA::class)
@ConditionalOnProperty("service.b")
@Service
class ServiceB(
private val serviceA: ServiceA
) {
init {
logger.info { "B SERVICE depends on $serviceA" }
}
}
@ConditionalOnBean(ServiceB::class)
@ConditionalOnProperty("service.c")
@Service
class ServiceC(
private val serviceB: ServiceB
) {
init {
logger.info { "C Service depends on $serviceB" }
}
}
Со следующим application.yml
:
service:
a: false
b: true
c: true
затем Spring при запуске вылетает со следующим:
**************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in org.gotson.transitivebeandependencies.ServiceC required a bean of type 'org.gotson.transitivebeandependencies.ServiceB' that could not be found.
Action:
Consider defining a bean of type 'org.gotson.transitivebeandependencies.ServiceB' in your configuration.
Вот результат автоконфигурации:
Positive matches:
ServiceC matched:
- @ConditionalOnProperty (service.c) matched (OnPropertyCondition)
- @ConditionalOnBean (types: org.gotson.transitivebeandependencies.ServiceB; SearchStrategy: all) found bean 'serviceB' (OnBeanCondition)
Negative matches:
ServiceA:
Did not match:
- @ConditionalOnProperty (service.a) found different value in property 'service.a' (OnPropertyCondition)
ServiceB:
Did not match:
- @ConditionalOnBean (types: org.gotson.transitivebeandependencies.ServiceA; SearchStrategy: all) did not find any beans (OnBeanCondition)
Matched:
- @ConditionalOnProperty (service.b) matched (OnPropertyCondition)
Однако со следующим application.yml
:
service:
a: true
b: false
c: true
тогда все работает нормально, создается только экземпляр ServiceA
, а бины ServiceB
и ServiceC
не создаются.
То же самое поведение с @Bean
вместо @Component
работает как ожидалось.
MyBeans.kt
:
private val logger = KotlinLogging.logger {}
@Configuration
class MyBeans {
@ConditionalOnProperty("bean.a")
@Bean
fun beanA(): BeanA {
logger.info { "A BEAN" }
return BeanA("beanA")
}
@ConditionalOnBean(BeanA::class)
@ConditionalOnProperty("bean.b")
@Bean
fun beanB(beanA: BeanA): BeanB {
logger.info { "B BEAN depends on $beanA" }
return BeanB("beanB")
}
@ConditionalOnBean(BeanB::class)
@ConditionalOnProperty("bean.c")
@Bean
fun beanC(beanB: BeanB): BeanC {
logger.info { "C BEAN depends on $beanB" }
return BeanC("beanC")
}
}
data class BeanA(val name: String)
data class BeanB(val name: String)
data class BeanC(val name: String)
С application.yml
:
bean:
a: false
b: true
c: true
Я не получаю бобов типа BeanA
, BeanB
или BeanC
экземпляров.
Вот результат автоконфигурации:
Negative matches:
MyBeans#beanA:
Did not match:
- @ConditionalOnProperty (bean.a) found different value in property 'bean.a' (OnPropertyCondition)
MyBeans#beanB:
Did not match:
- @ConditionalOnBean (types: org.gotson.transitivebeandependencies.BeanA; SearchStrategy: all) did not find any beans (OnBeanCondition)
Matched:
- @ConditionalOnProperty (bean.b) matched (OnPropertyCondition)
MyBeans#beanC:
Did not match:
- @ConditionalOnBean (types: org.gotson.transitivebeandependencies.BeanB; SearchStrategy: all) did not find any beans (OnBeanCondition)
Matched:
- @ConditionalOnProperty (bean.c) matched (OnPropertyCondition)
Я настроил образец репо с тестами для воспроизведения: https://github.com/gotson/spring-transitive