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. istio分布式调用链Jaeger

    1.安装 kubectl apply -n istio-system -f https://raw.githubusercontent.com/jaegertracing/jaeger-kuberne ...

  2. 关系测试# 或 print(s2-s)Python 集合

    1集合是一个无序的,不重复的数据组合,它的主要作用如下(set和dict类似,也是一组key的集合,但不存储value.由于key不能重复,所以,在set中,没有重复的key): 去重,把一个列表变成 ...

  3. matlab函数拟合

    1 函数拟合 函数拟合在工程(如采样校正)和数据分析(如隶属函数确定)中都是非常有用的工具.我这里将函数拟合分为三类:分别是多项式拟合,已知函数类型的拟合和未知函数类型的拟合.matlab中关于函数的 ...

  4. OpenSource.SerializationLibrary

    1. Cap'n Proto protocol buffer的主要作者之一创建的新项目.其主页描述Cap'n Proto的性能比PB快很多. http://kentonv.github.io/capn ...

  5. java mina框架使用

    1.目前为止,看到写mina最清晰的一篇博客:https://my.oschina.net/ielts0909/blog/85946! 2.官网的开发文档:http://mina.apache.org ...

  6. Mysql 注入load_file常用路径

    WINDOWS下: c:/boot.ini //查看系统版本 c:/windows/php.ini //php配置信息 c:/windows/my.ini //MYSQL配置文件,记录管理员登陆过的M ...

  7. openssl 连接 https(nginx)

    参考源码路径  demos\ssl #include <stdio.h> #include <string.h> #include <stdlib.h> #incl ...

  8. Java在dos界面运行java源文件编译成功,但运行虚拟机时出现错误:“找不到或无法加载主类”的问题

    (一)首先检查环境变量配置有没有问题, 1PATH为%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 2CLASSSPATH为.;%JAVA_HOME%\lib\dt.jar; ...

  9. Reading CLR via c# 4th Edition

    In fact, at runtime, the CLR has no idea which programming language the developer used for thesource ...

  10. Syslog和Windows事件日志收集

    Syslog和Windows事件日志收集 EventLog Analyzer从分布式Windows设备收集事件日志,或从分布式Linux和UNIX设备.交换机和路由器(Cisco)收集syslog.事 ...