wKiom1nYl-jD_XwmAAAnevpU4QE930.png

今天,以ClassPathXmlApplicationContext为例来看一下,Spring启动的时候都做了什么

wKiom1nYmJqj4-piAAAawDSEZ4w307.png

Spring学习笔记之启动_第1张图片

重点看refresh()方法

refresh()方法是在AbstractApplicationContext类中定义的

ClassPathXmlApplicationContext间接继承AbstractApplicationContext

Spring学习笔记之启动_第2张图片

这里面每一行代码的注释都写得很清楚我就不废话了,一行一行往下看

第1步、准备刷新上下文(PS:就不细看了)

第2步、获取BeanFactory


Spring学习笔记之启动_第3张图片

AbstractApplicationContext中的refreshBeanFactory()方法是一个抽象方法,咱们看一下具体实现。具体实现实在AbstractRefreshableApplicationContext类中。

Spring学习笔记之启动_第4张图片

可以看到,如果Bean工厂存在,则销毁,然后重新创建,不存在,则新建。

Spring学习笔记之启动_第5张图片

可以看到,新创建的Bean工厂是new了一个DefaultListableBeanFactory。

有了Bean工厂以后,接下来加载Bean定义。

本示例中loadBeanDefinitions()方法是在AbstractXmlApplicationContext类中定义的。

AbstractXmlApplicationContext间接继承AbstractRefreshableApplicationContext,同时,也是ClassPathXmlApplicationContext的直接父类。

Spring学习笔记之启动_第6张图片

至于,它到底是怎么加载,怎么解析的,这里就不细说了,很复杂

Spring学习笔记之启动_第7张图片

总之呢,到此为止,BeanFactory也获取到了,Bean定义也加载了。

接下来,回到refresh()

第3步、准备BeanFactory

Spring学习笔记之启动_第8张图片

这里,对传入的BeanFactory做了一系列配置,比如,类加载器,表达式解析器,BeanPostProcessor。反正,到此为止,BeanFactory已经创建并配置完成,接下来第4步调用postProcessBeanFactory()方法,这个方法是为子类预留的,就是一个后置回调,允许子类在BeanFactory初始化之后做一些事情。

第5步、实例化并调用所有已经在BeanFactory中注册了的BeanFactoryPostProcessor

Spring学习笔记之启动_第9张图片

Spring学习笔记之启动_第10张图片

Spring学习笔记之启动_第11张图片


这里补充一点,DefaultListableBeanFactory是实现了BeanDefinitionRegistry接口的。

wKioL1nYpPeSirYsAAArPfK9pk8993.png

Spring学习笔记之启动_第12张图片

第6步、实例化并且调用所有已经注册的BeanPostProcessor(PS:注意,是BeanPostProcessor,而不是BeanFactoryPostProcessor,BeanFactoryPostProcessor是在上一步中完成的。从这里我们也可以看出BeanFactoryPostProcessor和BeanPostProcessor的执行顺序。)

Spring学习笔记之启动_第13张图片

Spring学习笔记之启动_第14张图片

Spring学习笔记之启动_第15张图片

这里,从Bean定义中找到所有BeanPostProcessor类型的定义然后注册他们

第7步、初始化Message Resource

第8步、初始化时间广播器

第9步、初始化子类中其它的Bean,这里为子类留了一个口子

第10步、注册监听器

第11步、实例化所有的单例的非懒加载的Bean(PS:就是scope=singleton,并且lazy-init=false的Bean)

Spring学习笔记之启动_第16张图片

接下来,看看DefaultListableBeanFactory是怎么实现的

Spring学习笔记之启动_第17张图片

Spring学习笔记之启动_第18张图片


这里初始化所有非懒加载的单例Bean

重点看getBean()方法

Spring学习笔记之启动_第19张图片

接着往下看doGetBean()

Spring学习笔记之启动_第20张图片

看到有一个createBean方法

Spring学习笔记之启动_第21张图片

Spring学习笔记之启动_第22张图片

Spring学习笔记之启动_第23张图片

Spring学习笔记之启动_第24张图片

Spring学习笔记之启动_第25张图片

前面,费了那么大的劲就是做一些校验啊之类的,最终获得了RootBeanDefinition,有了这个东西之后就可以实例化了。

在上面的createBeanInstance方法中,

(1)如果这个类不是public的话,抛异常

(2)这个Bean的定义中有工厂方法,则使用它自带的工厂方法实例化

(3)如果需要自动装配,就用构造器装配实例化

(4)如果都不是,就用普通的方式实例化,其实就是用默认的构造器实例化

Spring学习笔记之启动_第26张图片

实例化之前,这里要获取实例化的策略。

那么,有哪些策略呢?

Spring学习笔记之启动_第27张图片

wKiom1nYvYnwn75EAAAycONNf5I487.png

Spring学习笔记之启动_第28张图片


这里,我们可以清楚的看到,默认的策略是Cglib

用Cglib返回的是代理对象

另外,还有一种就是普通的用默认构造方法实例化,这种返回的是真实对象。

接下来,还有最后一步

第12步、初始化LifecycleProcessor,并调用其onRefresh()方法,然后发布ContextRefreshedEvent事件


到此为止,AbstractApplicationContext的refresh()方法算是讲完了。

下面总结一下:

第1步、准备刷新

第2步、加载Bean定义,并获取BeanFactory,这里获取的是DefaultListableBeanFactory

第3步、配置BeanFactory,包括配置类加载器、配置BeanPostProcessor

第4步、调用postProcessBeanFactory()方法,这个方法是给子类预留的

第5步、实例化并调用所有注册的BeanFactoryPostProcessor

第6步、实例化并调用所有注册的BeanPostProcessor

第7步、初始化message resource

第8步、初始化事件广播器

第9步、调用onRefresh()方法,这是一个模板方法,是给子类预留的

第10步、注册监听器

第11步、完成BeanFactory的初始化,并且实例化所有的非延迟加载的单例(scope=singleton,lazy-init=false)Bean

第12步、初始化LifecycleProcessor,并调用其onRefresh()方法,然后发布ContextRefreshedEvent事件


到此结束!!!

最后,补充两点:

第一点是onRefresh()方法

Spring学习笔记之启动_第29张图片

第二点是,当第一次调用getBean()方法时会触发依赖注入,从上面的第11步中我们可以看到,大部分Bean在Spring启动的时候就已经完成了依赖注入。注入是在AbstractAutowireCapableBeanFactory类的populateBean方法完成的。

第三点是,Spring对Bean的依赖关系提供了两种方式:

(1)显式方式:通过BeanDefinition中的属性和构造方法,即通过构造方法的形式将依赖的Bean传入进来

(2)自动装配(autowiring):容器会自动使用反射查找属性的类型和名称,然后基于属性的类型或者名称来自动匹配容器中管理的Bean,从而自动地完成依赖注入。

Spring学习笔记之启动_第30张图片