概述
我们首先来看一下spring的大体架构图
基础接口
Resource+ResourceLoader
我们写的配置文件xml或者注解等等形式在spring看来都属于Resource
资源,而spring也提供了一个ResourceLoader
来加载我们写的资源
BeanFactory
我们先来看一下beanfactory的继承关系 beanFactory的接口就是定义了一些获取bean的基本方法,没有什么特别的 接下来看bean下面的三个接口
- HierarchicalBeanFactory
只是定义了一下beanFactory的父子关系 2. ListableBeanFactory 官方文档里面定义这个接口就是让人可以比较好的遍历容器里面的bean所设计出来的,所以我们也能看到新增的接口返回了bean的名称数组
DefaultListableBeanFactory
在上面看了BeanFactory的子接口后我们来看一个实现类,我们首先看一下 GenericApplicationContext
类,这个类是我们常用的IOC容器的父类 我们可以看到在这个类中有一个成员变量 DefaultListableBeanFactory
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
bean的名称映射
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
根据类型和名称的映射
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
只有单利的类和名称映射
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
获得所有bean信息
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
复制代码
这个类就是spring的信息中心,包含所有bean的定义信息
,但是他跟我们使用的ioc容器不是继承关系而是组合关系
BeanDefinition
BeanDefinition描述了一个bean的实例,可以获得bean名称,作用域,是否懒加载等等属性。
BeanDefinitionRegistry
一个BeanDefinition的注册中心,里面包含了BeanDefinition的映射关系
ApplicationContext
包含了很多功能,从继承接口可以看出,包含了ioc事件派发器,国际化解析,bean工厂,资源解析功能
Aware
在spring中有非常多的XXXAware,用了之后就可以获得到对象实例
BeanDefinition信息注册到BeanDefinitionRegistry流程
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Cat bean = context.getBean(Cat.class);
System.out.println(bean);
}
复制代码
代码很简单,现在来debug看spring注册流程
- 在
ClassPathXmlApplicationContext
的构造方法里执行了refresh方法
2. refresh是 AbstractApplicationContext
的方法,又调用了obtainFreshBeanFactory
让子类刷新内部的beanFactory 3. 随后调用了 AbstractRefreshableApplicationContext
类的 refreshBeanFactory方法。我们可以看到在这里创建了一个 DefaultListableBeanFactory
,然后把该对象传入子类的loadBeanDefinition
方法 4. 来到AbstractXmlApplicationContext
类的loadBeanDefinition,根据DefaultListableBeanFactory创建了一个XMLBeanDefinitionReader
然后读取配置文件 5. XMLBeanDefinitionReader
的doLoadBeanDefinition方法中,根据配置文件生成Document对象然后读取 随后再创建了一个 BeanDefinitionDocumentDocumentReader
,调用registerBeanDefinitions方法读取数据 6. 在BeanDefinitionDocumentDocumentReader 的内部有一个代理类,解析数据其实都是该类实现的 方法内遍历每一个节点解析数据 然后解析内部就是判断xml标签走不同的方法 7. 在解析bean的方法内部先封装了一个 BeanDefinitionHolder
组合了bean的名称和BeanDefinition
,然后调用一个工具类解析数据 8. 工具类内部调用 DefaultListableBeanFactory
的 方法注册Bean信息到档案馆 9. 现在正式来到DefaultListableBeanFactory
内部,首先会判断这个beanName是否已经在BeanDefinitionMap中存在,如果不存在就添加到map里面,并且也会添加一个名字列表到数组中
创建单实例Bean流程
我们刚才看的是Bean的定义信息已经被保存到spring中,我们现在来看看Spring创建实体对象的流程。
- 还是
AbstractApplicationContext
类的refresh方法,方法走到了finishBeanFactoryInitialization
方法,该方法主要设置了一些beanFactory的一些参数然后调用preInstanceSingletons
方法
2. 这个beanFactory就是那个DefaultListableBeanFactory
,方法中通过遍历之前已经初始化好的BeanDefinitionNames,创建不是抽象,是单例,不是懒加载的对象 3. 方法来到了父类AbstractBeanFactory
中的doGetBean
方法中,这个方法有很多逻辑,我们先来看首次创建的逻辑 4. 做了上面一系列判断之后,调用父类DefaultSingletonBeanRegistry
的getSingleton方法,方法中还会有一个回调,先不看父类的方法逻辑,直接看回调方法的createBean
,这是一个抽象方法,由子类AbstractAutowireCapableBeanFactory
实现 5. 执行一些暂时无意义的方法之后来到了instantiateBean
方法,内部有一个创建bean的策略类,实现有jdk的反射和cglib 6. spring在创建bean的过程中会判断该对象是否有重写的方法,如果有的话就走gclib,没有就走jdk默认
Bean属性赋值过程
我们上面看完了Bean实例的创建过程再来看一下Bean内部的属性是如何被spring注入进来的。在AbstractAutowireCapableBeanFactory
的doCreateBean方法中创建完bean实例之后继续往下执行
- 在doCreateBean方法内部,实例化bean后调用
populateBean
方法给bean属性赋值
2. 在populateBean方法中,如果是注解的方式启动的spring则会走后置处理器的方式来赋值对象,如果是xml的形式则会走另一个方法,现在大部分都是注解的方式启动的容器,所以我们直接看后置处理器的方式 3. 在初始化完bean之后spring会执行容器中的所有InstantiationAwareBeanPostProcessor
对象的postProcessProperties方法,在方法中获得一个InjectionMetadata
对象,该对象就有需要注入的对象和方法,后面就是直接调用invoke方法就可以了。 4. 我们再来看看spring是如何寻找@Autowire
注解的,在上面方法的第一行的方法findAutowiringMetadata
进去 可以看到其实返回的数据是调用buildAutowiringMetadata
方法 该方法是从目标类一直循环上去,找属性是不是有目标注解 遍历集合判断是否有数据 数据的初始化就是添加这些注解
spring的后置处理器
spring提供了三种后置处理器
BeanFactoryPostProcessor
BeanPostProcessor
InitializingBean
我们来依次看每个后置处理器的执行流程。
BeanFactoryPostProcessor
首先还是回到refresh方法中,我们可以看到在创建普通bean对象的上面有个方法叫invokeBeanFactoryPostProcessor,从方法名就可以看出是执行BeanFactoryPostProcessor方法 方法内部调用了一个代理类的静态方法 方法内部会首先拿出实现了PriorityOrdered
接口的对象排序后执行
执行完PriorityOrdered
接口后再拿出实现了Order
接口的对象执行 最后把剩下的BeanFactoryPostProcessor根据类名排序后调用方法,这时候容器里面还是没有对象的,在getBean的时候需要走原来看过的创建普通bean的流程 前面的都是执行的BeanDefinitionRegistryPostProcessor
的方法postProcessBeanDefinitionRegistry
,三个判断结束之后最后执行BeanFactoryPostProcessor
的postProcessBeanFactory
方法 流程图如下
工厂后置增强的实际用途
我们现在知道了spring提供了一些工厂的后置处理器来增强工厂,那么我们现在来看看spring中实际使用工厂后置处理器做了什么事情,我们来看一个类ConfigurationClassPostProcessor
这个类是用于处理写了@Configuratioin
注解的类 排序好之后就在一个循环里面解析容器里面的类 在方法中先判断是不是需要跳过,如果写了@Conditional
注解的对象会判断条件是否生效 真正解析配置类的方法里面就是各种判断注解的情况,然后去做相应的方法
BeanPostProcessor 注册
工厂的增强至此就结束了,接下来看看普通组件的后置处理器的逻辑,还是回到refresh方法,这次是调用registerBeanPostProcessors
方法,注册后置处理器。 注册的逻辑跟BeanFactory都是由同一个代理类来完成的 大部分逻辑和bean工厂的逻辑一致,都是判断优先级接口的就先执行 跟bean工厂不一致的是,bean工厂的后置处理器直接执行目标方法,这里只是把bean后置处理器创建好之后就放入list中
InstantiationAwareBeanPostProcessor
所有的BeanPostProcessor都被注册之后,我们来看其中一个分支:InstantiationAwareBeanPostProcessor
的流程
SmartInstantiationAwareBeanPostProcessor
从名字上可以看出叫智能的
实例后置处理器,那么这个我们就来看看智能在什么地方. 在refresh方法中调用了一个注册监听器的方法 在该方法中调用了一个根据类型获取名称列表
的方法,该方法是ListableBeanFactory
接口的一个方法 为了获得目标类的名称,spring遍历所有的bean的名称,一个一个判断
判断逻辑是先判断已经初始化好的实例,然后再判断bean定义信息,如果都没有则让别人来判断 拿到容器中的SmartInstantiationAwareBeanPostProcessor然后把类名和bean名称穿进去,让实现类来决定 总结流程图 所以我们知道,在spring中,根据类型来找名称其实spring需要遍历所有对象,是一件很麻烦的事情
InstantiationAwareBeanPostProcessor
在spring容器创建对象之前,会先调用 InstantiationAwareBeanPostProcessor的 postProcessBeforeInstantiation
方法尝试返回对象,如果用户返回了则会用用户创建的对象。 如果没有则调用doCreateBean方法,方法内也会从一个缓存中获取,没有的话就继续调用方法创建 创建逻辑会让用户返回一个构造函数,注意这里调用的是SmartInstantiationAwareBeanPostProcessor的一个方法,如果没有就用默认的无参构造函数,之后就是上面写过的用工具类创建的方式
MergedBeanDefinitionPostProcessor
在创建好bean实例对象之后会调用一下MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法让用户定义一下BeanDefinition
PopulateBean
之后就进入属性赋值方法,首先会先执行 InstantiationAwareBeanPostProcessor
的 postProcessAfterInstantiation方法,返回bool类型的值,如果返回true则会继续属性赋值,返回false则不会属性赋值 如果返回true则开始执行InstantiationAwareBeanPostProcessor
的 postProcessProperties方法。自动注入 AutowiredAnnotationBeanPostProcessor
的该方法就实现了自动注入的属性赋值
PropertyValues
在上面我们可以看到postProcessProperties方法返回了一个pvs,我们也可以自定义返回pvs,spring最后会帮我们注入到对象中,创建一个PVS返回即可
BeanPostProcessor
属性赋值之后spring会执行initializeBean
方法初始化bean,首先会先执行一些 Aware
的注入
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
初始化的流程如下 postProcessBeforeInitialization
方法在调用初始化方法之前执行,让用户可以不断的包装对象
,有一个返回了null,则结束循环 返回对象之后就执行初始化方法,InitializingBean
的方法就是在这里被触发 执行完初始化方法之后,spring会调用postProcessBeforeInitialization
的另一个生命周期方法,同样也是让用户可以包装几层