博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
context:annotation-config和context:component-scan
阅读量:6687 次
发布时间:2019-06-25

本文共 8915 字,大约阅读时间需要 29 分钟。

hot3.png

一、XML配置方式

         现在有三个类ClassA、ClassB和ClassC,ClassA和ClassB、ClassC不在同一个包下,其中ClassA中有两个引用属性classB和classC,它们分别是ClassB和ClassC的实例。

package com.codeproject.jackie.springdive.beanconfig.yyy;public class ClassB {  public ClassB() {    System.out.println("creating instance of ClassB :" + this);  }}package com.codeproject.jackie.springdive.beanconfig.yyy;public class ClassC {  public ClassC() {    System.out.println("creating instance of ClassC :" + this);  }}package com.codeproject.jackie.springdive.beanconfig.xxx;import com.codeproject.jackie.springdive.beanconfig.yyy.ClassB;import com.codeproject.jackie.springdive.beanconfig.yyy.ClassC;public class ClassA {  private ClassB classB;  private ClassC classC;  public ClassA() {    System.out.println("creating instance of ClassA :" + this);  }  public void setClassB(ClassB classB) {    System.out.println("setting field classB with " + classB + " in ClassA");    this.classB = classB;  }  public void setClassC(ClassC classC) {    System.out.println("setting field classC with " + classC + " in ClassA");    this.classC = classC;  }}

    下面是相应的XML配置:   

         加载Spring容器后输出以下结果:

creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@10d09ad3creating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@4178460dcreating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@3f3f210fsetting field classB with com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@10d09ad3 in ClassAsetting field classC with com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@4178460d in ClassA

二、注解配置方式

         使用注解就是为了简化XML配置,下面对上面的例子做些改动。在ClassA中的setter方法上增加@Autowired注解。

package com.codeproject.jackie.springdive.beanconfig.xxx;       import com.codeproject.jackie.springdive.beanconfig.yyy.ClassB;       import com.codeproject.jackie.springdive.beanconfig.yyy.ClassC;       import org.springframework.beans.factory.annotation.Autowired;       public class ClassA {           private ClassB classB;           private ClassC classC;           public ClassA() {               System.out.println("creating instance of ClassA :" + this);           }           @Autowired           public void setClassB(ClassB classB) {               System.out.println("setting field classB with " + classB + " in ClassA");               this.classB = classB;           }           @Autowired           public void setClassC(ClassC classC) {               System.out.println("setting field classC with " + classC + " in ClassA");               this.classC = classC;           }       }
         
XML配置文件修改如下:   
          
再次加载Spring容器,输出以下结果:
creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@48082d37creating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@10aadc97creating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@4178460d

          从结果中我们可以发现属性classB和classC没有自动注入到ClassA中。

        这是因为我们还缺少能够找到并处理这些注解的工具---注解处理器,注解本身并不能够做任何其它事情,它们只是用来注释一些东西。

三、<context:annotation-config>

         为了让Spring能够自动装配属性classB和classC以解决上面的问题,可以在XML文件注册AutowiredAnnotationBeanPostProcessor这个Bean后处理器。

           
通常我们会采用一种更优雅的方式---即使用
<context:annotation-config>。

        <context:annotation-config>会隐式地向Spring容器中AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor以及RequiredAnnotationBeanPostProcessor这四个Bean后处理器。注册这四个Bean后处理器的作用是为了在系统中识别并激活相应的注解,@Autowired、@Resource @PostConstruct@PreDestroy、@PersistenceContext以及@Required等注解

        现在将XML配置文件修改如下:

          
再次加载Spring容器,输出结果如下:
creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@236527fcreating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@59556d12 creating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@1a0fced4 setting field classB with com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@236527f in ClassA setting field classC with com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@59556d12 in ClassA
         
输出的确是我们想要的结果。但是XML配置文件并没有简化多少。下面我删掉XML中的bean声明并使用用
@Component
注解来替换它们。 
    
package com.codeproject.jackie.springdive.beanconfig.yyy;       import org.springframework.stereotype.Component;       @Component       public class ClassB {           public ClassB() {               System.out.println("creating instance of ClassB :" + this);           }       }       package com.codeproject.jackie.springdive.beanconfig.yyy;       import org.springframework.stereotype.Component;       @Component       public class ClassC {           public ClassC() {               System.out.println("creating instance of ClassC :" + this);           }       }       package com.codeproject.jackie.springdive.beanconfig.xxx;       import com.codeproject.jackie.springdive.beanconfig.yyy.ClassB;       import com.codeproject.jackie.springdive.beanconfig.yyy.ClassC;       import org.springframework.beans.factory.annotation.Autowired;       import org.springframework.stereotype.Component;       @Component       public class ClassA {           private ClassB classB;           private ClassC classC;           public ClassA() {               System.out.println("creating instance of ClassA :" + this);           }           @Autowired           public void setClassB(ClassB classB) {               System.out.println("setting field classB with " + classB + " in ClassA");               this.classB = classB;           }           @Autowired           public void setClassC(ClassC classC) {               System.out.println("setting field classC with " + classC + " in ClassA");               this.classC = classC;           }       }
    
而XML文件中只保留下面这个:
        
加载Spring容器后发现什么都没有输出,
没有创建bean,也没有注入bean
。为什么呢?
       这是
因为 
<context:annotation-config /> 仅仅作用于在Spring容器中注册过的bean
。由于我删掉了XML文件中那三个bean的定义所以没有bean被创建,
<context:annotation-config />
 也就没有了作用目标。
 

四、<context:component-scan>

        Spring通过<context:component-scan>提供了强大的组件扫描功能,在这个XML元素中必须指定base-package这个属性,其值即为要扫描的包,Spring会自动扫描指定的包和子包下所有使用了@Component、@Repository、@Service以及@Controller注解的类,将它们注册为Spring bean。其中@Component注解是基本注解,@Repository、@Service和@Controller分别表示持久层、服务层和表现层中的组件

       下面使用<context:component-scan>来简化XML配置:

          
再次
加载Spring容器,
 得到正确的输出结果:
creating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@1fbbd7b2 creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@34d507e9 setting field classB with com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@34d507e9 in ClassA creating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@214a7a12 setting field classC with com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@214a7a12 in ClassA
          
现在将XML配置文件修改如下: 
          
加载Spring容器,也可以得到正确的结果:
creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@bb273cc creating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@45660d6 creating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@3288df60 setting field classB with com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@bb273cc in ClassA setting field classC with com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@45660d6 in ClassA
          
可见,即使id为
classA的这个
bean不是通过包扫描而是在XML文件中手工注册的, 注解处理器仍被<context:component-scan>应用于所有在Spring容器中注册的bean上,亦即
<context:component-scan>有着和
<context:annotation-config />相同的功能

       那如果在XML配置文件中同时指定了<context:annotation-config/>和 <context:component-scan>呢? 

     
没有重复注册id为classA的这个bean,再一次获得了期望的结果:
creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@bb273cccreating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@45660d6creating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@3288df60setting field classB with com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@bb273cc in ClassAsetting field classC with com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@45660d6 in ClassA
         
这是因为两个标记注册了相同的注解处理器 (如果指定了<context:component-scan>那么<context:annotation-config />就会被忽略) ,但是Spring只会运行它们一次。

       即使你自己注册注解处理器多次,Spring将仍然保证只执行一次。修改XML配置如下:

           
我们仍然得到了正确的输出:   
creating instance of ClassB :com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@70d05c13creating instance of ClassC :com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@42ef83d3creating instance of ClassA :com.codeproject.jackie.springdive.beanconfig.xxx.ClassA@3801318bsetting field classB with com.codeproject.jackie.springdive.beanconfig.yyy.ClassB@70d05c13 in ClassAsetting field classC with com.codeproject.jackie.springdive.beanconfig.yyy.ClassC@42ef83d3 in ClassA

五、总结

       <context:annotation-config>是用来激活那些已经在Spring容器里注册过的bean(无论是通过xml还是包扫描定义的)上面的注解,而<context:component-scan>除了具有<context:annotation-config>的功能之外,它还可以扫描package来查找并注册bean。

六、参考资料

        

转载于:https://my.oschina.net/jackieyeah/blog/300987

你可能感兴趣的文章
Java中throws和throw的区别讲解
查看>>
Linux TOP命令详解
查看>>
不算完美的实现了自动化部署的进度实时更新
查看>>
Android2.2 API 中文文档系列(4) —— Manifest
查看>>
js 克隆
查看>>
Spring Boot:Data Rest Service
查看>>
二叉树学习笔记之经典平衡二叉树(AVL树)
查看>>
[C/C++基础知识] 一篇就让你彻底搞懂qsort快速排序的文章
查看>>
Dubbo架构设计详解
查看>>
JMeter基础之一 一个简单的性能测试
查看>>
磁带机Media is unrecognized
查看>>
DH密钥交换非对称加密
查看>>
程序员的量化交易之路(19)--Cointrader之Bar实体(7)
查看>>
存储过程中用到的年,月,周的函数
查看>>
IE7下元素的 'padding-top' 遇到 'clear' 特性在某些情况下复制到 'padding-bottom'
查看>>
IOS开发--常用工具类收集整理(Objective-C)(持续更新)
查看>>
[Android]getevent,sendevent,input命令的使用
查看>>
开始转移精力,研究BI方向
查看>>
Android配置----adb工具的使用
查看>>
TNS-12502: TNS:listener received no CONNECT_DATA from client
查看>>