天天看点

一文带你深入了解IOC启动原理

# 1. IOC概述

**1.1 是什么?**

**两个概念:控制反转,依赖注入**

**来看一下传统的干活方式:**在对象单一职责原则的基础上,一个对象很少有不依赖其他对象而完成自己的工作,所以这个时候就会出现对象之间的依赖。而体现在我们的开发中,就是需要什么对象的时候,就创建什么对象,此时对象创建的控制权在我们自己手里。当对象创建的太多的时候,就会出现一个对象更改,就得更改所有依赖它的对象,耦合性大。**自主性体现的同时也出现了对象耦合严重的情况**。

- 这个时候,我们就会思考,能不能我们在用的时候直接拿到这个对象去用,而将创建对象的能力交给第三方,这样我们就不需要关心对象是怎么创建的了。即将自己的控制权交出去。**这就是控制反转**

- 这个时候,就会有另一个问题产生了,**对象怎么才能直接被我们拿来用呢**。对象创建的时候,我们把这个对象注入到这个对象中,然后就可以使用了。**这就是依赖注入**

- **另一个问题,耦合性怎么被解决掉的?**通过控制反转我们仅仅使用了这个对象,如果对象发生了修改,我们仅仅需要修改第三方创建对象的方式即可,这个时候难道还会出现所谓的对象耦合吗?

- Spring全家桶地址:[Spring最新全家桶资料。](https://mp.weixin.qq.com/s/-_uuUbG7jsS639_q_K8rvA)

# 2. IOC架构

![](https://upload-images.jianshu.io/upload_images/24630328-31e2d0c75a5fb340.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

一个图搞定,**这个就是IOC的架构思路,这不是其执行流程图**。

我们接下来一步一步来解读。

**2.1 白话版**

在第一章中我们了解了IOC是来帮助我们**管理和创建对象**的。

这个时候我们需要一个承载我们需要创建信息的容器,即图中的XML或者注解,那么有了我们自己的BeanDefiniton信息以后,我们需要一个接口用来读取这些信息,于是出现了BeanDefinitionReader用来读取我们自己的Bean信息。

**那么我们需要考虑一个问题了,那么多的对象怎么生产呢?**

答案就是工厂模式。Spring默认的工厂是DefaultListableBeanFactory,没错,Spring中的所有对象(容器对象和我们自己创建的对象)都是由他创建的。**大批量生产对象**

这个时候又有了一个问题,我们不想通过BeanFactory直接生产了,需要对这个工厂进行一些特定处理,于是出现了BeanFactoryPostProcessor,用来对工厂做一些特定的处理。**我们自己可以通过实现这个接口,进行自定义BeanFactory**。又有兄弟说了:**我想单独创建一些我喜欢的对象,安排**,FactoryBean诞生了,它可以帮助我们创建一个我们需要的对象(**第四部分详细解释他们之间的区别**)。

**那又有兄弟说了:我想让统一的对象创建之前按照我的方式进行一些特殊的行为,简单,安排:see\_no\_evil**

BeanPostProcessor出现了,他提供了两个方法:一个在对象实例化之后初始化之前,执行内部的Before方法,在初始化之后,执行After方法。(**Bean生命周期,第四部分详解**)

**这个时候有兄弟有疑问了,不是说BeanPostProcessor在创建对象之前执行吗?怎么是创建完毕以后才执行的Before方法。**

如果各位兄弟了解过**指令重排序**这个概念,那么一定会听过一个案例,创建一个对象需要三步

- 创建空间(实例化)

- 初始化

- 赋值

**其中在初始化和赋值会出现指令重排序**

根据这个点,应该可以get到一个点,实例化和初始化不一样。

**所以又引出了一个点,我们对Bean进行一些操作,怎么操作,肯定是修改属性,或者添加一些属性等等,需要等待其在堆中开辟空间即实例化完成以后执行吧。**

所以BeanPostProcessor的before方法在实例化之后执行,初始化之前执行。

经历过前面一大堆的操作以后,终于我们的对象进入我们兜里了(容器里)。

关于销毁,一般情况下我们通过ApplicationContext拿不到其销毁方法,只能通过其子类实现获取,关于销毁同样的流程,先执行一个销毁之前的操作,然后再销毁。

**2.2 实际工作流程**

看过Spring源码或者听过的都知道里面有一个方法叫做refresh,他完成了好多事情。当然他的行为也代表了整个IOC容器加载和实例化对象的过程。**第三章的代码解读中我们仔细看**

![](https://upload-images.jianshu.io/upload_images/24630328-f53ca5049490da04.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**执行过程:**

- 加载配置文件,初始化系统环境Environment接口

- 准备上下文环境,初始化一些配置资源

- 创建一个工厂

- 为工厂添加各种环境

- 获取子类自己重写的BeanFactoryPostProcessor

- 执行容器和我们自己的BeanFactoryPostProcessor

- 注册BeanPostProcessor

- 国际化处理

- 转播器

- 子类初始化Bean

- 注册监听器,观察者模式

- 完成Bean创建

- 发布相应的事件,监听器

# 3. IOC源码解读

**3.1 上下文配置启动**

![](https://upload-images.jianshu.io/upload_images/24630328-369ff820a7a62675.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

在创建ClassPathXmlApplicationContext的时候,构造方法中执行了这些方法。

**说白了,加载了一个解析配置文件路径的加载器;然后又通过系统环境变量拿到这个配置文件,进行一些配置文件的去空格,转换表达式等等操作(没有进行解析);最后就是那个被我标成红色东东,refresh方法中它完成了几乎所有的工作。下面细聊**

**3.2 refresh**

![](https://upload-images.jianshu.io/upload_images/24630328-94b06e38b2d62aa6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个方法几乎完成了所有的操作,创建工厂,执行Processor等等,实例化对象,开启事件监听等等。

**接下来细聊**

**3.3.1 prepareRefresh()**

这个方法的主要作用是为应用上下文的刷新做一些准备性的工作。校验资源文件,设置启动时间和活跃状态等。

**3.3.2 obtainFreshBeanFactory()**

![](https://upload-images.jianshu.io/upload_images/24630328-604e9c07136c8c03.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**可以get到,它主要就是创建了一个工厂BeanFactory,并且解析了配置文件,加载了Bean定义信息(面试的时候直接答这个点就够了,如果想说的可以将下面的bean信息加载聊聊)没错,标红的就是咱接下来细聊的点**

![](https://upload-images.jianshu.io/upload_images/24630328-91ee0ec32d1bc2d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**这个就是加载配置文件的过程,注意:此时仍然没有解析,解析在标红的下面**

![](https://upload-images.jianshu.io/upload_images/24630328-aea1fa2c8606f2f4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**这个就是读取的过程,具体解析流程来自parse中,这个直接调用了Java中的解析XML的类库,有兴趣自行翻阅,最后返回了一个Document对象。**

**通过Document对象,读取内部的标签,执行不同的方法,逻辑和MyBatis中解析配置文件的思想相同,大家自行翻阅。**

**此时所有的Bean定义信息都被保存到了BeanDefinitionRegistry接口,然后走子类DefaultListableBeanFactory工厂的注册方法**

![](https://upload-images.jianshu.io/upload_images/24630328-40a855a97b621e13.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**3.3.3 prepareBeanFactory(beanFactory)**

为BeanFactory准备一些环境,方便在实例化的时候使用,同时添加容器自己的BeanPostProcessor

![](https://upload-images.jianshu.io/upload_images/24630328-69016bcc04c5b4e9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**3.3.4 postProcessBeanFactory**

留给子类扩展的BeanFactoryPostProcessor,

**3.3.5 invokeBeanFactoryPostProcessors(beanFactory)**

这个类,涉及到了两个接口。

- BeanFactoryPostProcessor

- BeanDefinitionRegistryPostProcessor接口,这个接口是BeanFactoryPostProcessor的子接口,**它的优先级比BeanFactoryPostProcessor更高**

它的总体执行流程是:先执行BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor,然后再执行BeanFactoryPostProcessor

**下图是BeanDefinitionRegistryPostProcessor接口的处理过程**

![](https://upload-images.jianshu.io/upload_images/24630328-5ae2fa0d5462ca9e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**BeanFactoryPostProcessor的处理逻辑**

总逻辑就是先分类,已经处理过的直接跳过,没有处理过的,分类处理,逻辑和上面的相同。

**3.3.6 registerBeanPostProcessors**

**这个方法的逻辑和上面的一样,只不过上面是直接执行了BeanFactoryPostProcessor,而这个仅仅注册没执行。**

![](https://upload-images.jianshu.io/upload_images/24630328-96a2519775e83b89.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

首先拿到工厂中所有的BeanPostProcessor类型的Bean,然后分类处理,排序注册。

**3.3.7 initMessageSource()**

执行国际化内容

**3.3.8 initApplicationEventMulticaster**

创建了一个多播器,为添加Listener提供支持。

**主要逻辑:**

- 容器中是否存在applicationEventMulticaster,如果存在直接注册

- 如果不存在,创建一个SimpleApplicationEventMulticaster,注册到容器中。

**3.3.9 onRefresh()**

子类扩展

**3.3.10 registerListeners()**

观察者模式的实现

![](https://upload-images.jianshu.io/upload_images/24630328-1dc4eef08b505869.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**3.3.11 finishBeanFactoryInitialization**

> 这一部分的内容太多了,所以采用代码和图解的方式来讲解。

![](https://upload-images.jianshu.io/upload_images/24630328-b6b4819d800cf22f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**下图是创建Bean的主要流程**

![](https://upload-images.jianshu.io/upload_images/24630328-2c6b94f182afe82f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**按照图中的序号一个一个说:**

1. BeanDefinition是否需要合并。BeanDefinition根据不同类型的配置文件信息,会将Bean封装到不同的Bean信息定义类中。比如我们常用的配置文件版的GenericBeanDefinition;注解扫描版的ScannedGenericBeanDefinition等等。

而在这个过程中就出现了,**父定义和子定义**,我们需要在实际处理定义信息的时候进行合并处理,主要有以下三个方面

- 存在父定义信息,使用父定义信息创建一个RootBeanDefinition,然后将自定义信息作为参数传入。

- 不存在父定义信息,并且当前BeanDefinition是RootBeanDefintion类型的,直接返回一份RootBeanDefintion的克隆

- 不存在父定义信息,并且当前BeanDefintion不是RootBeanDefintiton类型的,直接通过该BeanDefintion构建一个RootBeanDefintion返回

**上面的流程也是源码中的执行流程**

![](https://upload-images.jianshu.io/upload_images/24630328-52ffd6265cce2e33.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

1. isFactoryBean。判断是否为FactoryBean

**简单介绍一下:**FactoryBean是让开发者创建自己需要Bean接口。内部提供了三个方法

![](https://upload-images.jianshu.io/upload_images/24630328-93cfeb426006c1ca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

当我们通过GetBean直接该Bean的时候,获取到的是该工厂指定返回的Bean类型。如果想要获取该Bean本身,需要通过一个前缀获得&

![](https://upload-images.jianshu.io/upload_images/24630328-f3ff73161f2a9b0e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**再来看一个点,这个就是从容器中获取Bean的主要方法,也是解决循环依赖的逻辑**

![](https://upload-images.jianshu.io/upload_images/24630328-6336dfb7268d61ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**来聊一下它是怎么解决循环引用的?**

它引入了一个三级缓存的概念

![](https://upload-images.jianshu.io/upload_images/24630328-6e69de70544a353b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

在发生循环引用的时候,它首先通过ObejctFactory工厂将Bean创建出来,**此时的对象并没有进行属性赋值,仅仅在堆中开辟了空间。**然后将此时的Bean添加到earlySingletonObjects容器里,**也就是说这个容器中保存的Bean都是半成品。**而在之后的属性赋值中,由于对象为单例的,所以其引用地址不会发生变化,即对象最终是完整的。

1.getBean。**通过这个方法直接创建了所有的对象,这也是Spring最核心的方法了,先来看一下它整体的一个流程**

![](https://upload-images.jianshu.io/upload_images/24630328-130c4e443a1955d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**它的主要逻辑是:**

- 先拿到当前要实例化的Bean的真实名字,主要是为了处理FactoryBean,拿到以后,从当前容器中看是否已经创建过该Bean,如果存在直接返回。

- 如果不存在,获取其父工厂,如果父工厂不为空,而且当前容器中不存在当前Bean的信息,则尝试从父工厂中获取Bean定义信息,进行Bean实例化

- 如果父工厂为空,将当前Bean信息存放到alreadyCreated缓存中。

- 获取当前Bean的合并信息(getMergedLocalBeanDefinition),查看当前Bean是否存在依赖,如果存在则判断当前Bean和依赖 Bean 是否为循环依赖,如果不是循环依赖则先创建依赖Bean

- 判断当前Bean的作用域。

- 如果当前Bean是单例对象,直接创建Bean实例

- 如果当前Bean是多例对象,将当前Bean信息添加到正在创建多例缓存中,创建完毕以后移除

- 如果当前Bean是其他类型,如Requtst,Session等类型,则自定义一个ObejctFacotry工厂,重写getObject方法,创建对象

- 对象创建以后,判断当前对象是否为自己需要的对象,如果是直接返回;如果不是进行类型转换,如果类型转换失败,直接抛异常

接下来看一眼CreateBean的执行

![](https://upload-images.jianshu.io/upload_images/24630328-e364d52179dc4913.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**这个方法主要完成的事情是:通过Bean的名字拿到对应的Class对象;如果当前Bean获取到的Class对象不为空且该RootDefintiton可以直接获取到该Bean,克隆一份Bean定义信息,方便之后使用。**

**验证当前Bean上的@Override信息。执行BeanPostProcessor,返回一个代理对象(如果存在代理的话), 如果不存在代理,则直接创建Bean**

接下来我们来聊一下这个玩意——**resolveBeforeInstantiation**

![](https://upload-images.jianshu.io/upload_images/24630328-447beca04a70fb38.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**来吧,继续,看一下那个前置处理器逻辑**

![](https://upload-images.jianshu.io/upload_images/24630328-56b0dc59169c99ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

后置处理器就不看了,就调用了所有的后置处理器,然后执行了一遍,没有其他逻辑。

**接下来继续我们的正题:doCreateBean**

![](https://upload-images.jianshu.io/upload_images/24630328-afca1fd5dd4a377b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**其大致流程如上图:**

先判断以后是否单例,然后从FactoryBean缓存中看一下是否存在正在创建的Bean,如果存在拿出,如果不存在则创建一个当前Bean的包装类实例。然后拿到这个类的实例和实例类型,执行以后后置处理器。

当前Bean是否为单例,是否允许循环依赖,时候正在进行创建,如果是,创建一个当前Bean的ObejctFactory以解决循环依赖的问题

填充Bean的属性,进行Bean的实例化。

查看早期容器缓存中(缓存中的二级缓存中是否有该Bean)。如果有,则说明存在循环依赖,则进行处理

**先看循环依赖吧**

![](https://upload-images.jianshu.io/upload_images/24630328-b547121432d3d1e1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**接着来,createBeanInstance**

![](https://upload-images.jianshu.io/upload_images/24630328-56e4aa2b0dae9e91.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**Spring提供了三种方式创建对象的包装:**

- 通过供给者对象对象直接创建。obtainFromSupplier

- 通过工厂方法直接创建。

- 默认创建。构造方法是否需要自动注入构造方法不需要自动注入,调用默认的构造方法

**这个方法执行完毕以后,你应该知晓的一个点是:此时对象实例已经创建了,剩下的就是执行一系列增强器和初始化方法,属性填充等等。**

我们按照代码执行顺序来,属性填充即populateBean

这个方法执行逻辑:

- 首先判断传入的Bean是否为null,如果为null则判断Bean定义信息中是否存在属性值,如果存在,异常;如果不存在跳过

- 当前Bean定义信息是否为合并以后的,如果是且此时的工厂中存在InstantiationAwareBeanPostProcessors,那么在属性填充之前进行修改Bean的信息

- 拿到所有的属性值,解析属性值的自动注入方式,Type或者Name,进行自动注入

- 判断是否存在InstantiationAwareBeanPostProcessors,修改之前设置的属性

- 判断是否存在依赖检查,检查依赖

- 属性赋值

![](https://upload-images.jianshu.io/upload_images/24630328-8bf0ffcba60f2c1c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

接下来看执行初始化方法,就是调用BeanPostprocessor,init等方法

![](https://upload-images.jianshu.io/upload_images/24630328-55910de5c5244972.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**这个就是这个方法的执行流程图,相信到这个地方,大家应该对于为什么BeanPostProcessor的before方法会在init方法执行了解了。这个方法的作用仅仅是用来进行一个生命周期的打印,对象在之前已经创建了。**

----

**接下来看一下销毁的方法。registerDisposableBeanIfNecessary**

对于单例Bean来说,Spring将需要销毁的Bean存放到了disposableBeans缓存中,通过DisposableBeanAdapter封装了销毁Bean

对于其他作用域来说,自定义了销毁回调函数,不过最后还是封装为DisposableBeanAdapter

在封装为DisposableBeanAdapter的过程中,会首先判断该Bean中是否存在destroy方法,然后给赋值给destroyMethodName变量。再次判断这个方法的参数,如果参数的个数大于1,则抛出异常

![](https://upload-images.jianshu.io/upload_images/24630328-4d5e0cd35715e080.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**3.3.12 finishRefresh**

这个方法进行了一系列的资源清理和

![](https://upload-images.jianshu.io/upload_images/24630328-76b5de6e309d1499.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

initLifecycleProcessor,这个方法极具简单,就看一下当前Bean中是否存在生命周期处理器,如果存在直接使用这个,如果不存在则创建一个默认的,并且注册为一个单例的扔到容器中。