IOC源码流程细致过程解析
文章目录
控制反转
源码流程
- this()方法主要是调用该类中的其他重载构造函数,这里调用的是无参构造;但是众所周知:子类调用无参构造会首先调用父类的构造,所以这里会调用–
- 同时继续调用父类抽象类的构造初始化一些原始数据;
- 这些都调用完毕后回到开始的构造方法AnnotationConfigApplication中,发现实例化了一个bean的读取器;那他有什么用处呢?
实例化建BeanDefinition读取器: AnnotatedBeanDefinitionReader:
作用:做两件事:注册spring依赖的各种后置处理器beanPostProcessor、注册相关的beanDifinition,用来后续的bean工厂创建bean;
- 源码探究,点进Reader的构造方法中去;首先看他如何注册后置处理器Processors
- 所以顺道而行,继续点进去看看如何注册
- 当然详细展开就是判断容器中是否已经存在了ConfigurationClassPostProcessor的 Bean;如果不存在就注册bean定义,挑出一个看流程,其他也是一样的执行流程;
- 到了这一步,我们会产生一个疑问,BeanDifinition是什么,为什么铺垫了这么久就为了注册它?别急我来解释它
BeanDifinition解释
-
其实它就是用来描述Bean的,里面存放着关于Bean的一系列信息,比如Bean的作用域,Bean所对应的Class,是 否懒加载,是否Primary等等,这个BeanDefinition也相当重要,我们以后会常常和它打交道。
回到这个方法中,我们发现他又调用了一个注册方法将beanName和definition注册,
- 所以我们走进这个方法,发现他是个接口,那么具体调用那个实现类呢? 当然是beanFactory这个实现类啦;
- 如果去集合里面没拿到,就说明需要注册;那会走什么样的逻辑呢?先思考一个问题:如果有多个线程同时进入到这里,难道需要同时注册?然后Map里面出现两个一模一样的?显然这样是不合理的,所以到这我们需要做一个判断,该bean是否正在创建:
-
主要是这个加锁有点难以理解,其他都好说;至此,bean工厂的所有原料 添加完毕,就等工厂开工生产!
-
之后就是创建扫描器,这个扫描器只是提供给外部手动调用的,没多大用处;
注册配置类:
好家伙,内置的类全注册了,但是我们自定义的类呢?不慌,把目光回到开始
点进去!最终来到doRegister
-
在这里又要说明下,以常规方式去注册配置类,此方法中除了第一个参数,其他参数都是默认值。
-
通过AnnotatedGenericBeanDefinition的构造方法,获得配置类的BeanDefinition,这里是不是 似曾相似,在注册ConfigurationClassPostProcessor类的时候,也是通过构造方法去获得 BeanDefinition的,只不过当时是通过RootBeanDefinition去获得,现在是通过 AnnotatedGenericBeanDefinition去获得。
-
判断需不需要跳过注册,Spring中有一个@Condition注解,如果不满足条件,就会过这个类的 注册。
-
然后是解析作用域,如果没有设置的话,默认为单例。
-
获得BeanName。
-
解析通用注解,填充到AnnotatedGenericBeanDefinition,解析的注解为Lazy,Primary, DependsOn,Role,Description。
-
限定符处理,不是特指@Qualifier注解,也有可能是Primary,或者是Lazy,或者是其他(理论上 是任何注解,这里没有判断注解的有效性)。
-
把AnnotatedGenericBeanDefinition数据结构和beanName封装到一个对象中(这个不是很重 要,可以简单的理解为方便传参)。
-
注册,最终会调用DefaultListableBeanFactory中的registerBeanDefinition方法去注册:
-
- 到这里就已经把配置类注册进去了!
其实到这里只是Spring的冰山一角,我们目前只知道了spring是如何注册内置的bean和我们的配置类而已,我们还没扫描呢,还没创建bean呢!不急!
refresh()
prepareBeanFactory(beanFactory);这个方法需要了解一下,主要有以下功能
- 主要是invokeBeanFactoryPostProcessors这个方法,里面做了很多事情;这个方法巨他妈长!(我不想写了。。。)
首先明确他的任务:把之前加入的后置处理器给实例化,我们不是加入了许多后置处理器么( BeanFactoryPostProcessor ),这里的目的就是首先把他们实例化出来,然后调用他们内部的方法!所以带着这个任务去阅读源码,寻找我们需要的信息
但是我们想一下,我们注册了五个后置处理器,他以什么样的规则来实例化执行呢?这里先给出结论:
分类: BeanFactoryPostProcessor 分为两种
- BeanFactoryPostProcessor
- BeanDefinitionRegistryPostProcessor 第二种继承了第一种!
spring机制要求先处理直接实现了第二种的Post Processor,然后处理直接实现了第一种的;
在处理每一种Post Processor时,还要分优先级情况PriorityOrdered, Ordered。
所以流程就是
整体上流程如下:
1.处理BeanDefinitionRegistryPostProcessor
-------1.1 处理PriorityOrdered优先级的
-------1.2处理Ordered优先级的
-------1.3处理其他优先级的
打开一看继承关系发现:
只有一个后置处理器实现了他,所以把它处理了就ok了!
2.处理BeanFactoryPostProcessor
-------2.1 处理PriorityOrdered优先级的
-------2.2处理Ordered优先级的
-------2.3处理其他优先级的
-------ok进源码,先BeanDefinitionRegistryPostProcessor
拿到ConfigProcessor之后就可以实例化了
接下来就可以看看实例化的代码,这是很重要的一环
getBean---->creatBean
点击getbean后发现是个接口
那么那会调用哪一个实现类呢?答案是 第二个,那么直接点进去来到dogetBean();
- 很好理解,这里首先肯定从缓存拿,如果之前实例化了当然就不用重新实例化了!还有就是spring做了很多检查,如果bean工厂被销毁了或者bean定义在其他线程实例化了当然就会产生相应的问题啦!
接着往下看
@DependsOn注解遇到循环依赖就会抛出异常了,举个例子
来看运行结果:
不就是上面源码中的那个异常吗?看来Spring并没有解决这种循环依赖的办法?或者是我孤陋寡闻------
接着往下看
如何创建bean的呢?这里可能涉及循环依赖,当然我们第一步的话是实例化ConfigrationProcessor这个类,这个类是不会有循环依赖的,毕竟他的功能就是实例化出来后用来扫描bean,
看源码如何创建的
每一个类在实例化之前都会调用后置处理器,然后再实例化,关于实例化docreatBean里面有很处理了循环依赖的问题导致稍微难理解,这回单独放在一章来讲解
后置处理器的九次调用,上上图中的resolveBeforeInstantiationjiushi 第一次;方法中判断是否实现的 hasInstantiationAwareBeanPostProcessors 这个接口,实现了就会调用方法;
简单介绍一下doCreatBean的主要流程打个照面
1.首先使用bean的构造方法创建bean;
2.执行MergedBeanDefinitionPostProcessor类型的后置处理器回调方法,利用反射技术,遍历类中的属性和方法,并判断属性和方法上的注解信息;
比如CommonAnnotationBeanPostProcessor.java,用于发现并缓存@Resource等注解修饰的属性;
比如AutowiredAnnotationBeanPostProcessor.java,用于发现并缓存@Autowired/@Value等注解修饰的属性;
等等。
3.提前缓存earlyBeanReference引用,就是实例化还没初始化的bean信息,用于后边处理循环依赖。
4.populateBean填充bean,就是初始化bean的属性值;如果属性是个bean,此处需要实例化依赖的bean,并缓存到一个叫earlySingletonObjects的map中;
5.initializeBean执行init或者post processors,动态代理也发生在这一步;
6.最终返回创建好的bean对象。
之后的其他各种后置处理器走一样的流程;
之后还有几个方法:分别作用是:
这些就是IOC的流程了!
解决几道面试题
1.BeanFactory和FactoryBean的区别?
- BeanFactory主要是是容器的一个基础设施,就是一个门面,我们可以到那获取想要的bean,而FactoryBean则是用于创建具体的bean,我们可以实现他的接口完成我们自己想要实现的bean;
2.请介绍BeanFactoryPostProcessor在Spring中的用途。
- 作为spring主要扩展点;旨在提供相应接口给用户实现,从而完成用户需要的功能;比如在bean生命周期的九次后置处理器调用们都为了能在bean创建时期实现对bean的动态拓展和更改,保证容器的多样性以及灵活性,根据后置处理器把IOC前期需要的诸多类资源通过扩展点的方式准备完整,义工后续bean创建的使用;主要作用还是定制和 修改bena定义内容;比如Aop就是在bean初始化后调用后置处理器为其创建动态代理,实现本插入功能代码段;
3.SpringIoC的加载过程。
- 首先肯定是往bean工厂中添加生产bean的原料—beandifinition;再者之前当然得扫描和注册bean定义;把注册bean需要的一些工具类和一些内置的原始的后置处理器优先和配置类一起注册到bean工厂中;
- 然后优先将他们实例化供后续使用,例如用来解析注解的CongifationProcessor后置处理器;等这些创世纪de类实例完成后开始解析配置类;
- 解析完毕就可以创建bean,不过在此之前还会调用后置处理器postBefore····用来阻止bean创建,当然如果用户实现了特定的接口的话
- 从bean工厂中拿到bean定义准备实例化,利用反射和构造方法实例化对象;当然如果有多个构造函数这么办呢,我们可以利用后置处理器调用方法指定构造方法实现自由选择;
- 实例化之后里面的属性不是还没填充嘛?属性上还有可能有自动装配的注解,@Autowired等;这时候就需要另一个后置处理器插足解析这些注解,如果含有依赖项就会优先实例依赖bean;
- 终于可以填充属性了,属性填充完毕就可以得到一个完整的bean了,然后就会调用初始化方法;
- 初始化结束后当然需要处理使用使用Aop,为其创建动态代理,可以发现这些拓展的功能都是依靠后置处理器来实现的!
4.Bean的生命周期。
5.Spring中有哪些扩展接口及调用时机。