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. ParseCrontab类,解析时间规则

    <?php /** * Created by PhpStorm. * User: ClownFish 187231450@qq.com * Date: 14-12-27 * Time: 上午11 ...

  2. .net序列化

    在开发过程中,会遇到很多需要使用序列化的场景,比如wcf,webservice或者jquery+.net等.那今天就说说我对序列化的理解. 在.net中有几种序列化的方式,XML.二进制.SOAP.还 ...

  3. HDU 3861.The King’s Problem 强联通分量+最小路径覆盖

    The King’s Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  4. UI设计初学者教程:色彩基础知识

    编辑:千锋UI设计 初学设计都会先认识三原色,通常我们说的三原色指的是颜料三原色:红.黄.蓝:其实三原色还有色光三原色:红.绿.蓝.我们通常说的红黄蓝就是减色法三原色,而红绿蓝是加色法三原色.可能这么 ...

  5. spring boot 无法启动

    spring boot 使用内置tomcat 报错  : Unable to start embedded Tomcat servlet container Tomcat connector in f ...

  6. PHP字符串替换函数

    str_replace函数 描述:实现字符串替换,区分大小写 语法:mixed str_replace(mixed $search, mixed replace, mixed $subject, [i ...

  7. Devexpress VCL Build v2015 vol 15.1.2发布

    2015年马上过半年了.终于第一个大版出来了. What's New in 15.1.2 (VCL Product Line)   New Major Features in 15.1 What's ...

  8. rails 辅助方法

    rails辅助方法全解: https://ruby-china.github.io/rails-guides/routing.html

  9. 693. Binary Number with Alternating Bits

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...

  10. ES6通过使用babel兼容到ie9

    1.打开这个地址: https://unpkg.com/babel-standalone@6/babel.min.js 新建babel.min.js,把代码复制进去,然后在jq项目里引用. 2.在下面 ...