spring里IOC的原理就不详细写了, 如果想要搞清楚自动扫描组件是如何实现的,还有@Resouce @PostConstruct等注解的工作原理,最好可以先搞清楚整个IOC容器的运作原理再来分析这个过程.

IOC容器里的bean的生命周期如下:

1. beanDefinition 的解析

2. beanDefinition 的注册

3. bean的实例化

4. bean 的依赖注入

5. bean的初始化 (在初始化前后分别有对BeanPostProcessor的应用)

当然,中整个过程中还有很多细节的部分, 比如循环依赖的解决, 是否惰性注入, 等等, 还少不了很多地方都有BeanPostProcessor的埋点调用.

以上都是对IOC的简单背景介绍, 下面开始说正文.

在解析xml的时候, 如果发现了context:component-scan 这个标签, 在解析xml的过程中,就会找到这个标签的parsre类, 也就是ComponentScanBeanDefinitionParser, 具体怎么找到这个解析器的, 请大家自行回顾下beanDefinition 的解析过程.

然后我们看下ComponentScanBeanDefinitionParser 里的parse方法, 一直追下去, 会看到把包下各个类当作resource返回, 然后使用ASM对类信息进行解析. 大家自己可以看下关于ASM的内容 , 在看源码的时候,会更容易理解.  可以看到在对类信息进行解析的时候, 其实只是记录了类级别的信息, 比较类名, 类上的注解 等等, 在解析到类内的方法和域的时候, 使用的都是一个空的visitor, 也就意味着, 在解析的过程中, 并没有对方法和域进行任何实质性的解析,也没有记录任何关于方法和域的信息. 然后就拿着类级别的信息, 生成了对应的beanDefinition, 然后将这些beanDefinition注册到容器里. 看到这里, 我本来是很困惑的, 没有对域和方法进行解析, 那这个类内部的依赖是怎么注入的呢?

下面开始解释@Resouce @PostConstruct 这类注解的生效原理

首先看@Resouce这个注解是怎么生效的.  我们可以看下CommonAnnotationBeanPostProcessor 这个类, 在postProcessPropertyValues 方法里往下追, 会看到对@Resouce 这个注解的识别, 还有相应的域信息的记录, 然后还有相应bean的获取, 还有进行注入等操作. 但是postProcessPropertyValues 这个方法是什么时候被调用的呢? 再分析一下调用链, 发现是在bean的依赖注入的过程中, 掉用了所有的InstantiationAwareBeanPostProcessor 的postProcessPropertyValues 方法,  来对使用了@Resouce注解的类进行依赖注入.  总结一下, 在整个bean的生命周期里, 都没有保持关于@Resouce这个注解的任何信息, 它的生效, 完全是同过一类BeanPostProcessor来实现. 这也是为什么在解析beanDefinition的时候, 没有解析任何关于类内部域和方法的原因

下面再说@PostConstruct 这个注解是怎么生效的. 原理是一样的, 这次我们看下InitDestroyAnnotationBeanPostProcessor 这个类, 内部的postProcessBeforeInitialization 方法, 可以看到, 在这个方法里 , 首先对@PostConstruct 这个注解进行识别, 然后通过反射, 对这个方法进行了调用. 而postProcessBeforeInitialization 这个方法的被调用的地方就是上面在bean的生命周期里提到的  5. bean的初始化 (在初始化前后分别有对BeanPostProcessor的应用)

好, 这个时候, 其实可以看到IOC的设计思路了, 很多的注解的功能的生效, 并不是在解析beanDefinition的时候, 先对这些注解的信息进行解析, 保留, 然后到对应的点直接调用.   而是在对应的点, 通过不同的BeanPostProcessor开始对类内部进行解析, 如果解析到了感兴趣的注解或别的元素的话, 直接开始调用.

那么我们还剩下最后一个问题, 这些BeanPostProcessor 是什么地方注册进去的呢? 我们回到ComponentScanBeanDefinitionParser 这个类里, 看下parse 这个方法里调用了registerComponents 这个方法,往下追, 会看到AnnotationConfigUtils.registerAnnotationConfigProcessors 的调用,在这里注册了很多的BeanPostProcessor, 其中就有CommonAnnotationBeanPostProcessor, 还有别的一些注解, 包括一些会@Autowired等注解处理的BeanPostProcessor. 这也就是为什么说  <context:component-scan base-package=”XX.XX”/> 这个配置其实包含了类如<context:annotation-config/> 这些配置的原因.....

好, 但是还有一点不对劲, 这里的对BeanPostProcessor的注册, 只是把这写BeanPostProcessor当作普通的beanDefinition向容器进行了注册, 这写beanDefinition是什么时候生成真正的bean实例, 并被注册成为容器的BeanPostProcessor的呢? 这时就需要看下AbstractApplicationContext 类里的refresh方法了. 在这里完成了很多的操作, 包括对容器的初始化, beandefinition的注册等等一些操作. 在这个方法里可以看到对registerBeanPostProcessors的调用, 这这里, 会找到已经注册了的beandefinition里的BeanPostProcessor, 然后对它们进行实例话, 然后把bean实例注册为容器真正的BeanPostProcessor

也就是说, 如果我们想要把自己写的BeanPostProcessor 在spring内生效的话, 只要继承BeanPostProcessor 这个接口, 然后把这个类向spring注册就好了

好了, 以上, 就是对自动扫描相关的解说, 希望对大家有帮助

转载请注明出处:  http://www.cnblogs.com/zhaoxinshanwei/p/8399176.html

spring启动component-scan类扫描加载,以及@Resource,postConstruct等等注解的解析生效源码的更多相关文章

  1. 【Spring源码分析系列】启动component-scan类扫描加载过程

    原文地址:http://blog.csdn.net/xieyuooo/article/details/9089441/ 在spring 3.0以上大家都一般会配置一个Servelet,如下所示: &l ...

  2. spring启动component-scan类扫描加载过程(转)

    文章转自 http://www.it165.net/pro/html/201406/15205.html 有朋友最近问到了 spring 加载类的过程,尤其是基于 annotation 注解的加载过程 ...

  3. 在Spring Boot中从类路径加载文件

    介绍 创建Spring Boot Web应用程序时,有时有时需要从类路径中加载文件:war和jar的加载文件格式是不一样的 在下面,您将找到在WAR和JAR中加载文件的解决方案. 资源加载器 使用Ja ...

  4. 鸿蒙内核源码分析(进程镜像篇)|ELF是如何被加载运行的? | 百篇博客分析OpenHarmony源码 | v56.01

    百篇博客系列篇.本篇为: v56.xx 鸿蒙内核源码分析(进程映像篇) | ELF是如何被加载运行的? | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应 ...

  5. spring启动component-scan类扫描加载过程---源码分析

    http://blog.csdn.net/xieyuooo/article/details/9089441#comments

  6. Spring Boot 启动(二) Environment 加载

    Spring Boot 启动(二) Environment 加载 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) 上一节中 ...

  7. 反射 类的加载 Schema DOM 解析方式和解析器 命名空间

    Day15 反射 1.1 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. l 加载 就是指将class文件读入内存,并为之创建 ...

  8. 【转】怎么解决java.lang.NoClassDefFoundError错误 ,以及类的加载机制

    转自http://blog.csdn.net/jamesjxin/article/details/46606307 前言 在日常Java开发中,我们经常碰到java.lang.NoClassDefFo ...

  9. jvm(1)类的加载(二)(自定义类加载器)

    [深入Java虚拟机]之四:类加载机制 1,从Java虚拟机的角度,只存在两种不同的类加载器: 1,启动类加载器:它使用C++实现(这里仅限于Hotspot,也就是JDK1.5之后默认的虚拟机,有其他 ...

随机推荐

  1. Java的OOP三大特征之一——继承

    Java的OOP三大特征之一——继承 子类继承父类的特征和行为(属性和方法),使得子类具有父类的各种属性和方法.或子类从父类继承方法,使得子类具有父类相同的行为. 特点:在继承关系中,父类更通用.子类 ...

  2. 20172306《Java程序设计与数据结构》第九周学习总结

    20172306<Java程序设计>第九周学习总结 教材学习内容总结 第十一章: try-catch语句.其中还有finally语句.try是进行某些操作,catch是捕获异常,并通过某些 ...

  3. PID参数调节口诀

    参数整定找最佳, 从小到大顺序查. 先是比例后积分, 最后再把微分加. 曲线振荡很频繁, 比例度盘要放大. 曲线漂浮绕大弯, 比例度盘往小扳. 曲线偏离回复慢, 积分时间往下降. 曲线波动周期长, 积 ...

  4. POJ 2449Remmarguts' Date 第K短路

    Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 29625   Accepted: 8034 ...

  5. jzoj P1163 生日派对灯

    在IOI98的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1到N被标上号码.这些灯都连接到四个按钮:  按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄灭,本来是 ...

  6. Spring 循环引用(二)源码分析

    Spring 循环引用(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环引用相关文章: & ...

  7. PHP 判断字符串括号是否匹配

    <?php function aa($str) { $temp = array(); for ($i = 0; $i < strlen($str); $i++) { $t = $str[$ ...

  8. 如何利用Photoshop进行快速切图

    在UI设计中我们常常使用Ai来进行矢量图的绘制,然后导入Ps中进行设计.排版和导出. 在以前的版本中,切图一直是个很麻烦的事情,要么依托于脚本,要么手动一张张导出,很不方便,这种窘况在Photosho ...

  9. mybatis 一次执行多条语句

    现在的一些互联网应用 为了提高性能,现在一般比较少的使用外键.不是不用,只是在创建数据库不标明外键关系,用程序去维护. 为了维护数据一致性,我们需要手动完成相关数据的删除 比如用户和用户的关注 当用户 ...

  10. java 中jar的使用

    ????????????这里不会 需要学习