<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. 协处理器CP15介绍—MCR/MRC指令(6)

    概述:在基于ARM的嵌入式应用系统中,存储系统的操作通常是由协处理器CP15完成的.CP15包含16个32位的寄存器,其编号为0-15. 而访问CP15寄存器的指令主要是MCR和MRC这两个指令. 例 ...

  2. 第1阶段——关于u-boot目标文件start.o中.globl 和.balignl理解(3)

    汇编程序中以.开头的名称并不是指令的助记符,不会被翻译成机器指令,而是给汇编器一些特殊指示,称为伪操作. .globl _start 作用:声明一个_start全局符号(Symbol), 这个_sta ...

  3. 团队作业10——复审与事后分析(Beta版本)

    Deadline: 2017-6-13 22:00PM,以博客发表日期为准 评分基准: 按时交 - 有分,检查的项目内容为后文的两个方面 Beta阶段项目复审(单独一篇博客) 事后诸葛亮分析报告(单独 ...

  4. Java GUI+mysql+分页查询

    1.要求 : 创建一个学生信息管理数据库 2.实现分页查询 代码如下: a)学生实体类: /** * @author: Annie * @date:2016年6月23日 * @description: ...

  5. 团队作业8——第二次项目冲刺(Beta阶段)--第六天

    一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 学号 成员 贡献比 201421123001 廖婷婷 16% 201421123002 翁珊 16% 201421123004 ...

  6. spring的list ,set,map,properties注入(set,get注入)

    ①Message.java: package com.hts.entity; import java.io.Serializable; import java.util.List; import ja ...

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

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代 ...

  8. 201521123063 《java程序设计》第六周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  9. 201521123039《java程序设计》第五周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 2. 书面作业 代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句 ...

  10. 201521123060《Java程序设计》第2周学习总结

    1. 本周学习总结 a.进一步熟悉了Eclipse的使用和java程序的编写: b.学习了java数据的基本类型:整数类型,浮点类型等: c.学习了算数运算符,赋值运算符,位运算符,关系运算符,逻辑运 ...