<context:annotation-config> 和 <context:component-scan>的区别

Difference between <context:annotation-config> vs <context:component-scan>

<context:annotation-config> 是用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解。

<context:component-scan>除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean 。

下面我们通过例子来详细查看他们的区别,

有三个class   A,B,C,并且B,C的对象被注入到A中.

[java] view plaincopy在CODE上查看代码片派生到我的代码片

01.package com.xxx; 

02.public class B { 

03.  public B() { 

04.    System.out.println("creating bean B: " + this); 

05.  } 

06.} 

07. 

08.package com.xxx; 

09.public class C { 

10.  public C() { 

11.    System.out.println("creating bean C: " + this); 

12.  } 

13.} 

14. 

15.package com.yyy; 

16.import com.xxx.B; 

17.import com.xxx.C; 

18.public class A {  

19.  private B bbb; 

20.  private C ccc; 

21.  public A() { 

22.    System.out.println("creating bean A: " + this); 

23.  } 

24.  public void setBbb(B bbb) { 

25.    System.out.println("setting A.bbb with " + bbb); 

26.    this.bbb = bbb; 

27.  } 

28.  public void setCcc(C ccc) { 

29.    System.out.println("setting A.ccc with " + ccc); 

30.    this.ccc = ccc;  

31.  } 

32.}

在applicationContext.xml中加入下面的配置 :

<bean id="bBean"class="com.xxx.B"/>

<bean id="cBean"class="com.xxx.C"/>

<bean id="aBean"class="com.yyy.A">

  <property name="bbb" ref="bBean"/>

  <property name="ccc" ref="cBean"/>

</bean>

加载applicationContext.xml配置文件,将得到下面的结果:

creating bean B: com.xxx.B@c2ff5

creating bean C: com.xxx.C@1e8a1f6

creating bean A: com.yyy.A@1e152c5

setting A.bbb with com.xxx.B@c2ff5

setting A.ccc with com.xxx.C@1e8a1f6

OK, 这个结果没什么好说的,就是完全通过xml的方式,不过太过时了,下面通过注解的方式来简化我们的xml配置文件

首先,我们使用autowire的方式将对象bbb和ccc注入到A中:

[java] view plaincopy在CODE上查看代码片派生到我的代码片

01.package com.yyy; 

02.import org.springframework.beans.factory.annotation.Autowired; 

03.import com.xxx.B; 

04.import com.xxx.C; 

05.public class A {  

06.  private B bbb; 

07.  private C ccc; 

08.  public A() { 

09.    System.out.println("creating bean A: " + this); 

10.  } 

11.  @Autowired 

12.  public void setBbb(B bbb) { 

13.    System.out.println("setting A.bbb with " + bbb); 

14.    this.bbb = bbb; 

15.  } 

16.  @Autowired 

17.  public void setCcc(C ccc) { 

18.    System.out.println("setting A.ccc with " + ccc); 

19.    this.ccc = ccc; 

20.  } 

21.}

然后,我们就可以从applicationContext.xml中移除下面的配置

<property name="bbb" ref="bBean"/>

<property name="ccc" ref="cBean"/>

移除之后,我们的applicationContext.xml配置文件就简化为下面的样子了

<bean id="bBean"class="com.xxx.B"/>

<bean id="cBean"class="com.xxx.C"/>

<bean id="aBean"class="com.yyy.A"/>

当我们加载applicationContext.xml配置文件之后,将得到下面的结果:

creating bean B: com.xxx.B@5e5a50

creating bean C: com.xxx.C@54a328

creating bean A: com.yyy.A@a3d4cf

OK, 结果是错误的的,究竟是因为什么呢?为什么我们的属性没有被注入进去呢?

是因为注解本身并不能够做任何事情,它们只是最基本的组成部分,我们需要能够处理这些注解的处理工具来处理这些注解

这就是<context:annotation-config> 所做的事情

我们将applicationContext.xml配置文件作如下修改:

<context:annotation-config />

<bean id="bBean"class="com.xxx.B"/>

<bean id="cBean"class="com.xxx.C"/>

<bean id="aBean"class="com.yyy.A"/>

当我们加载applicationContext.xml配置文件之后,将得到下面的结果:

creating bean B: com.xxx.B@15663a2

creating bean C: com.xxx.C@cd5f8b

creating bean A: com.yyy.A@157aa53

setting A.bbb with com.xxx.B@15663a2

setting A.ccc with com.xxx.C@cd5f8b

OK, 结果正确了

但是如果我们将代码作如下修改:

[java] view plaincopy在CODE上查看代码片派生到我的代码片

01.package com.xxx; 

02.import org.springframework.stereotype.Component; 

03.@Component 

04.public class B { 

05.  public B() { 

06.    System.out.println("creating bean B: " + this); 

07.  } 

08.} 

09. 

10.package com.xxx; 

11.import org.springframework.stereotype.Component; 

12.@Component 

13.public class C { 

14.  public C() { 

15.    System.out.println("creating bean C: " + this); 

16.  } 

17.} 

18. 

19.package com.yyy; 

20.import org.springframework.beans.factory.annotation.Autowired; 

21.import org.springframework.stereotype.Component; 

22.import com.xxx.B; 

23.import com.xxx.C; 

24.@Component 

25.public class A {  

26.  private B bbb; 

27.  private C ccc; 

28.  public A() { 

29.    System.out.println("creating bean A: " + this); 

30.  } 

31.  @Autowired 

32.  public void setBbb(B bbb) { 

33.    System.out.println("setting A.bbb with " + bbb); 

34.    this.bbb = bbb; 

35.  } 

36.  @Autowired 

37.  public void setCcc(C ccc) { 

38.    System.out.println("setting A.ccc with " + ccc); 

39.    this.ccc = ccc; 

40.  } 

41.}

applicationContext.xml配置文件修改为:

<context:annotation-config />

当我们加载applicationContext.xml配置文件之后,却没有任何输出,这是为什么呢?

那是因为<context:annotation-config />仅能够在已经在已经注册过的bean上面起作用。

对于没有在spring容器中注册的bean,它并不能执行任何操作。

但是不用担心,<context:component-scan>除了具有<context:annotation-config />的功能之外,还具有自动将带有@component,@service,@Repository等注解的对象注册到spring容器中的功能。

我们将applicationContext.xml配置文件作如下修改:

<context:component-scan base-package="com.xxx"/>

当我们加载applicationContext.xml的时候,会得到下面的结果:

creating bean B: com.xxx.B@1be0f0a

creating bean C: com.xxx.C@80d1ff

这是什么原因呢?

是因为我们仅仅扫描了com.xxx包及其子包的类,而class  A是在com.yyy包下,所以就扫描不到了

下面我们在applicationContext.xml中把com.yyy也加入进来:

<context:component-scan base-package="com.xxx"/>

<context:component-scan base-package="com.xxx,com.yyy"/>

然后加载applicationContext.xml就会得到下面的结果:

creating bean B: com.xxx.B@cd5f8b

creating bean C: com.xxx.C@15ac3c9

creating bean A: com.yyy.A@ec4a87

setting A.bbb with com.xxx.B@cd5f8b

setting A.ccc with com.xxx.C@15ac3c9

哇,结果正确啦 !

回头看下我们的applicationContext.xml文件,已经简化为:

<context:component-scan base-package="com.xxx"/>

<context:component-scan base-package="com.xxx,com.yyy"/>

了。

那如果我们在applicationContext.xml手动加上下面的配置,也就是说既在applicationContext.xml中手动的注册了A的实例对象,同时,通过component-scan去扫描并注册B,C的对象

<context:component-scan base-package="com.xxx"/>

<bean id="aBean"class="com.yyy.A"/>

结果仍是正确的:

creating bean B: com.xxx.B@157aa53

creating bean C: com.xxx.C@ec4a87

creating bean A: com.yyy.A@1d64c37

setting A.bbb with com.xxx.B@157aa53

setting A.ccc with com.xxx.C@ec4a87

虽然class  A并不是通过扫描的方式注册到容器中的 ,但是<context:component-scan> 所产生的的处理那些注解的处理器工具,会处理所有绑定到容器上面的bean,不管是通过xml手动注册的还是通过scanning扫描注册的。

那么,如果我们通过下面的方式呢?我们既配置了<context:annotation-config />,又配置了<context:component-scan base-package="com.xxx" />,它们都具有处理在容器中注册的bean里面的注解的功能。会不会出现重复注入的情况呢?

<context:annotation-config /><context:component-scan base-package="com.xxx"/><bean id="aBean"class="com.yyy.A"/>

不用担心,不会出现的:

creating bean B: com.xxx.B@157aa53

creating bean C: com.xxx.C@ec4a87

creating bean A: com.yyy.A@1d64c37

setting A.bbb with com.xxx.B@157aa53

setting A.ccc with com.xxx.C@ec4a87

因为<context:annotation-config />和 <context:component-scan>同时存在的时候,前者会被忽略。也就是那些@autowire,@resource等注入注解只会被注入一次

哪怕是你手动的注册了多个处理器,spring仍然只会处理一次:

[xml] view plaincopy在CODE上查看代码片派生到我的代码片

01.<context:annotation-config /> 

02.<context:component-scan base-package="com.xxx" /> 

03.<bean id="aBean" class="com.yyy.A" /> 

04.<bean id="bla" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> 


05.<bean id="bla1" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> 


06.<bean id="bla2" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> 


07.<bean id="bla3" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />

结果仍是正确的:

creating bean B: com.xxx.B@157aa53

creating bean C: com.xxx.C@ec4a87

creating bean A: com.yyy.A@25d2b2

setting A.bbb with com.xxx.B@157aa53

setting A.ccc with com.xxx.C@ec4a87

spring <context:annotation-config> 跟 <context:component-scan>诠释及区别的更多相关文章

  1. Spring注解详解@Repository、@Component、@Service 和 @Constroller

    概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...

  2. Spring 开启Annotation <context:annotation-config> 和 <context:component-scan>诠释及区别

    <context:annotation-config> 和 <context:component-scan>的区别 <context:annotation-config& ...

  3. spring 2.5.6 错误:Context namespace element 'component-scan' and its parser class [org.springframework.context.annotation.ComponentScanBeanDefinitionParser] are only available on JDK 1.5 and higher

    在运行一个第三方公司交付的项目的时候, 出现: Caused by: java.lang.IllegalStateException: Context namespace element 'annot ...

  4. Spring 配置 Annotation <context:annotation-config> 和 <context:component-scan>标签的诠释及区别

    Spring 开启Annotation <context:annotation-config> 和 <context:component-scan>诠释及区别 <cont ...

  5. (转)Spring开启Annotation<context:annotation-config> 和 <context:component-scan>诠释及区别

    转自:https://www.cnblogs.com/leiOOlei/p/3713989.html <context:annotation-config> 和 <context:c ...

  6. Spring配置之context:annotation与、component-scan以及annotation-driven

    spring boot帮助我们隐藏了大量的细节,有些配置spring boot都是开启的,因此当我们查看遗留项目使用spring时候遇见问题一定细心排查 <!-- context:annotat ...

  7. spring源码分析之<context:component-scan/>vs<annotation-config/>

    1.<context:annotation-config/> xsd中说明: <xsd:element name="annotation-config"> ...

  8. Mingyang.net:org.springframework.context.annotation.ConflictingBeanDefinitionException

    org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean ...

  9. Spring context:component-scan中使用context:include-filter和context:exclude-filter

    Spring context:component-scan中使用context:include-filter和context:exclude-filter XML: <?xml version= ...

随机推荐

  1. 前端AES的加密和解密

    在工作的过程中,经常要对一些数据做一些加密,当然有复杂的加密和简单的加密,也有对称加密等等.总之加密的方式有很多.今天在这里,我只是简单的分享一个我最近遇到的加密方式-AES.这个也是后端工程师用的, ...

  2. 团队作业4----第一次项目冲刺(Alpha版本)4.24

    a.提供当天站立式会议照片 会议内容: ①:对数据库的设计存在问题的进一步讨论 ②:讨论需求分析中的存在的难解决的问题,比如要做到较好的反应用户的行为. ③:分配今天的任务 b. 每个人的工作 工作完 ...

  3. Beta的计划和人员的变动

    一.新的成员和组长是否重选: 刘光华:先加入的一个帅哥,乐于助人,编码基础不是很好,但是有一颗热爱学习的心,会积极主动的完成自己的任务的,一句话宣言:我们的团队是最棒的! 程志铭:做事认真负责,工作脚 ...

  4. sudoku--设想

    在查阅了一些资料和自己动手写一写后,找到一种可行的解法. 第一步 首先将9x9的数独方格分成九份3x3的九宫格,如下图 B1 B2 B3 B4 B5 B6 B7 B8 B9 而后在左上角的B1上随机生 ...

  5. 201521123093 java 第八周总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 1.泛型简介:同一个代码可以被不同的对象重用 2.使用泛型的好处:允许 ...

  6. 201521123072《java程序设计》第四次总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.11.2 使用常规方法总结其他上课内容 一些小的方法归纳: 通过 instanceof 可以判断父类引用所引用的对象实例的实际类 ...

  7. 201521123110《Java程序设计》第12周学习总结

    1. 本周学习总结 2. 书面作业 1. 字符流与文本文件:使用 PrintWriter(写),BufferedReader(读) 1.1 生成的三个学生对象,使用PrintWriter的printl ...

  8. Java项目生成Jar文件

    打开 Jar 文件向导 Jar 文件向导可用于将项目导出为可运行的 jar 包. 打开向导的步骤为: 在 Package Explorer 中选择你要导出的项目内容.如果你要导出项目中所有的类和资源, ...

  9. GSON速学必会

    一. GSON 简介 GSON是一个用Java语言编写的用于处理JSON数据格式的开源应用程序编程接口项目.它将Java对象转换为JSON表示.还可以用于将JSON字符串转换为等效的Java对象. g ...

  10. 25个最基本的JavaScript面试问题及答案

    1.使用 typeof bar === "object" 来确定 bar 是否是对象的潜在陷阱是什么?如何避免这个陷阱? 尽管 typeof bar === "objec ...