<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. Nand Flash驱动(实现初始化以及读操作)

    简单制作一个Nand Flash驱动(只需要初始化Flash以及读Flash) 打开2440芯片手册,K9F2G08U0M芯片手册(因为2440中Nand Flash是用的256MB(2Gb)内存,8 ...

  2. SwaggerUI笔记

    关于 Swagger Swagger能成为最受欢迎的REST APIs文档生成工具之一,有以下几个原因: Swagger 可以生成一个具有互动性的API控制台,开发者可以用来快速学习和尝试API. S ...

  3. Swing-JDialog示例代码-用户登陆UI

    JDialog是一种对话框组件,它常常与JOptionPane配合使用.JOptionPane提供对话框内部的消息.按钮等内容,JDialog提供对话框窗体,提供模态/非模态等属性.JDialog与J ...

  4. 201521123034 《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前 ...

  5. 使用 Python & Flask 实现 RESTful Web API

    环境安装: sudo pip install flask Flask 是一个Python的微服务的框架,基于Werkzeug, 一个 WSGI 类库. Flask 优点: Written in Pyt ...

  6. Selenium_WebDriver_元素方法

    版权声明:本文为博主原创文章,转载请注明出处. 前面已经学习了定位元素,定位只是第一步,定位之后需要对这个元素进行操作,如在百度搜索首页的输入框进行输入文本,对"百度一下"按钮进行 ...

  7. webservice07#契约优先#webservice实现简单的动态web项目

    1, 用户管理 User{username,password,nickname} 属性. 2,契约优先[ 先用schema做标准来写wsdl.再生成服务器端的接口,再编写接口的类] 在src下创建目录 ...

  8. spring的一些问题

    1.什么是spring? spring是一个轻量级的一站式框架,它的核心有两个部分,1.aop面向切面编程 2.ioc控制反转. 2.什么是aop aop就是面向切面编程,使用aop可以使业务逻辑各个 ...

  9. 《Java从入门到放弃》JavaSE入门篇:网络编程(入门版)

    要进行网络编程,首先要搞清楚目的是什么. 网络编程说简单点就是在网络上的计算机进行数据的交互. 既然要进行数据交互,那就需要有一个发送方和一个接受方. 按网络上的说法,就是一个攻一个受· 当然,现阶段 ...

  10. merge 语法解析

    merge into 支持sqlserver 2008 和以上的版本 无论是INSERT还是UPDATE,从执行之间上看,MERGE INTO(MERGE)都要比直接INSERT/UPDATE的效率高 ...