java spring component与autowire区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java spring component与autowire区别相关的知识,希望对你有一定的参考价值。

这两个注解不是干一个事儿的啊,component相当于原来xml中把你标注了component注解的类注册成一个bean,autowired是默认按照类型自动装配 参考技术A 我来说一下,个人见解,欢迎指正。它们都是交给spring管理的意思,只不过要spring帮它们实现不同的功能而已。@component的作用是在文件开头加上这个后,就不用再在applicationContext.xml里面一个个地加bean了,省了这个步骤。而@autowire是引入一个对象后,交给了spring管理,用到的时候就不需要再通过new的方式获取对象了。 参考技术B 一个是自动起个名 一个是你想定义成什么类型啊或名字啥的去寻找

Spring Boot 传递 @Component 依赖与 @ConditionalOnBean

【中文标题】Spring Boot 传递 @Component 依赖与 @ConditionalOnBean【英文标题】:Spring Boot transitive @Component dependencies with @ConditionalOnBean 【发布时间】:2018-10-21 13:10:09 【问题描述】:

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

我使用@ConditionalOnBean 来避免实例化@Component,它依赖于由于缺少properties 而未实例化的其他@Component

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

让我试着用一个简单的例子来解释一下。

考虑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 的一个实例被实例化,而没有创建ServiceBServiceC bean。


使用@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

我没有实例化 BeanABeanBBeanC 类型的 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)

我已经设置了一个示例 repo,其中包含要重现的测试:https://github.com/gotson/spring-transitive

【问题讨论】:

有趣的是,我可以看到的第一个服务差异是 ConditionalOnPropertyPARSE_CONFIGURATION 阶段评估,ConditionalOnBeanREGISTER_BEAN 评估。 ServiceA 只有 onProperty 它没有注册,但 ServiceB 两者都有,而且 Spring,在寻找注册候选人时只检查PARSE_CONFIGURATION,这导致serviceB 在 beanFactory 中注册,并且 onBeanCondition 在 beanFactory 中检查现有的潜在 bean匹配,在真正创建它们之前。 我添加了自动配置报告的详细信息。很奇怪,ServiceC 是 @ConditionalOnBean 上的匹配项,而 ServiceB 不是。 【参考方案1】:

@ConditionalOnBean 是一个 bean 注册阶段检查,因此,需要对 ApplicationContext 中有效可用的 bean 有一个概述。可以使用常规@Bean 以标准方式注册Bean,公开与方法的返回类型相同的目标类型。您可能还拥有FactoryBean,其逻辑更复杂,可能导致我们必须处理的奇异设置。

无论如何,订购是关键。如果您希望 bean 类型匹配正常工作,则必须按给定顺序处理配置类。如果您有一个 C1 配置类,它仅在 bean B 可用并且该 bean 由 C2 提供时贡献一个 bean AC2 必须首先运行

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

您的设置完全避开了排序,因此如果排序正确,它就可以工作,如果不正确,它就不会。 @ConditionalOnBean的Javadoc明确states that

强烈建议仅在自动配置类上使用此条件。

如果您想了解更多信息,可以参加 3 小时的大学课程,涵盖,即这个主题 on youtube。

【讨论】:

非常感谢您的详细回答,我会尽可能看视频。回到我的问题,是否也与 @Component@Bean 的生命周期不同这一事实有关?我的理解是,即使排序正确,在组件扫描期间,@Component 注解生成的 bean 也会被添加到 bean 工厂中? 我不明白这个问题。它适用于@Bean,因为所有内容都在同一个类中,因此没有顺序问题,因为您只有一个源(MyBeans@Configuration 类)。这几乎就是我在回答中试图解释的内容。 实际上我更想了解为什么它不适用于@Component。我把@Bean的例子画了一个平行线。 我的回答解释了为什么它不能与@Component 一起使用(顺序不同,所以当我们检查 bean 是否存在时,它不存在所以条件失败,然后 bean 之后创建)。我真的不知道它的哪一部分不清楚。 这听起来完全不对,我也不会这样做。如果您按预期使用工具,它可能是可靠的。如果用户定义了 bean,则需要自动配置。而且创建一个并不难,所以我不明白这个问题。【参考方案2】:

这里的问题是您对控件的定义。

对于@Service 示例 (false,true,true),您的控件属性确定是否定义了服务。 ServiceA 没有定义也没有构造。 ServiceB 已定义,但未构造,因为没有 ServiceA 定义。定义 ServiceC 并尝试构建。如前所述,由于缺少 ServiceB 的实例,ServiceC 的构造失败。

对于@Bean 示例(false,true,true),您的控件属性确定是否构造 Bean。没有构造BeanA,没有构造BeanB,因为没有BeanA,没有构造BeanC,因为没有BeanB。

对于@Service 示例(true,false,true): ServiceA 已定义并构造,ServiceB 既未定义也未构造,ServiceC 已定义但未尝试构造,因为未定义 ServiceB。

用@Bean 修饰的方法在配置阶段生成一个由 Spring 容器管理的 bean。

用@Component (@Service) 修饰的Java 类将在组件扫描过程中被检测并注册为Spring bean。

因为@Service 注解不像@Bean 那样创建和注册组件,所以使用@ConditionalOnClass 代替@ConditionalOnBean 可能会产生你想要的结果。关于此注释有一些注意事项。

【讨论】:

感谢您的回答,但这并不能告诉我为什么上述方法不起作用,以及它是如何起作用的? 对不起,如果我的解释不清楚......关于“它如何工作?”问题,我加了一段。 @ConditionalOnClass 正在查看类路径,因为 jar 布局不会改变,它不会工作(我只是测试过)。我认为总而言之,这可能归结为使用 @Bean 注册的正确 Bean 和 Spring 通过 @Component 创建的隐式 Bean 之间的区别,但是我不明白为什么我的示例在这些概念下无法工作。

以上是关于java spring component与autowire区别的主要内容,如果未能解决你的问题,请参考以下文章

Quartz与Spring集成 Job如何自动注入Spring容器托管的对象

Spring中的@Service与@Component [重复]

java: spring注释:关于@component和@autowired

spring aspect为啥要加 component

Spring中如何混用XML与Java装配方式

Java spring 使用@Component默认返回的都是同一个对象吗?