我有一个Spring Boot 1.5.x项目,其中某些@Component依赖于其他@Component,最终沿着依赖关系链,可以使用@Component完全启用或禁用某些@ConditionalOnProperty

我正在使用@ConditionalOnBean来避免实例化依赖于其他@Component@Component,这些其他properties由于缺少MyServices.kt而尚未实例化。

但是,它仅适用于直接依赖关系,不适用于传递依赖关系,但是我不明白为什么。

让我尝试用一​​个简单的例子来解释。

考虑到application.yml:

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)

但是,使用以下ServiceA:
service:
  a: true
  b: false
  c: true

然后一切正常,仅实例化ServiceB实例,而未创建ServiceC@Bean Bean。

@Component而不是MyBeans.kt相同的行为可以正常工作。
application.yml:
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)

BeanA:
bean:
  a: false
  b: true
  c: true

我没有实例化类型为BeanBBeanC或ojit_code的bean。

这是自动配置的结果:
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

最佳答案

@ConditionalOnBean是Bean注册阶段检查,因此,需要概述ApplicationContext中有效使用哪些bean。可以使用常规的@Bean以标准方式注册Bean,从而公开与该方法的返回类型相同的目标类型。您可能还拥有带有更复杂逻辑的FactoryBean,这可能导致我们不得不处理异国情调的设置。

无论如何,订购是关键。如果要使Bean类型匹配正常工作,则必须按给定的顺序处理配置类。如果您有一个C1配置类,仅当bean A可用并且该bean由B贡献时,才贡献bean C2,则C2必须首先运行。

Spring Boot的解析阶段分为两个步骤:首先,我们解析所有用户的配置。完成后,我们将解析自动配置的bean定义。自动配置本身是有序的(使用@AutoConfigureBefore@AutoConfigureAfter)。这样,我们可以保证,如果您将@ConditionalOnBean放入自动配置中,则会按照用户配置的预期进行处理。而且,如果您依靠其他自动配置提供的功能,则可以使用这些注释轻松订购它。

您的设置完全可以避免订购,因此如果订购正确,则可以使用,如果订购不正确,则可以使用。 @ConditionalOnBean的Javadoc显然是states that



如果您想了解更多信息,可以参加3小时的大学类(class),即on youtube这个话题。

关于java - 使用@ConditionalOnBean的Spring Boot可传递的@Component依赖项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50286863/

10-10 19:59
查看更多