一、Spring 源码运行环境安装

  1. 环境版本:Gradel版本 5.6.3 JDK 11.0.5, Spring 5.1.12 <br /> 导入工程后 修改仓库地址为阿里云 加快依赖下载速度<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12497888/1611994503646-8cbe9a38-8d43-49d3-8ee5-c618673e625a.png#crop=0&crop=0&crop=1&crop=1&height=122&id=MYh8s&margin=%5Bobject%20Object%5D&name=image.png&originHeight=244&originWidth=1100&originalType=binary&ratio=1&rotation=0&showTitle=false&size=29370&status=done&style=none&title=&width=550)<br />项目导入之后编译⼯程(顺序:core-oxm-context-beans-aspects-aop) <br />⼯程—>tasks—>compileTestJava

二、 Spring IoC 容器初始化主体流程

1、容器接口

BeanFactory ->顶级容器/根容器 它定义了容器的基础行为
ApplicationContext 是容器的高级接口,继承至BeanFactory
Spring应用上下文, 称之为IoC容器,内部包含Map成员, map 在singleton模式中成为单例池
容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程
BeanFactory接口:
image.png
“&”前缀加名称可获取到FactoryBean(Bean工厂用于创建Bean)实例 image.png
BeanFactory 继承体系,不同的继承层级 具有不同的功能
image.png
ResourceLoader->加载资源
MessageSource->国际化支持
ListableBeanFactory->获取Bean集合接口工厂
HierarchicalBeanFactroy->获取父工厂
Spring将Bean相关接口 按功能进行分开定义接口,在使用时需要什么功能只需要继承相应的接口即可

2、Bean生命周期特殊时机点

(1)构造器方法(LagouBean())执行、
image.png
初始化方法(InitializingBean)执行
image.png
调用的是同一个类中相同的方法
AbstractApplicationContext #refresh=> #finishBeanFactoryInitialization(构造器/初始化方法执行)
image.png

(2)Bean工厂后置处理器初始化、方法执行
BeanFactory初始化执行:
image.png
构造初始化堆栈调用信息
image.png
后置处理器内方法执行
image.png
方法执行堆栈调用信息:
image.png
AbstractApplicationContext #refresh => #invokeBeanFactoryPostProcessors

(3)Bean后置处理器
Bean后置处理器构造器执行
image.png
对应堆栈调用信息: AbstractApplicationContext #refresh => #registerBeanPostProcessors
image.png

Bean后置处理器前初始化方法
image.png
调用堆栈信息:AbstractApplicationContext #refresh => #finishBeanFactoryInitialzation (同构造器和初始化方法)
image.png
后初始化方法执行
image.png
调用堆栈信息:AbstractApplicationContext #refresh => #finishBeanFactoryInitialzation (同构造器和初始化方法)
image.png

  • 构造器执行、初始化方法执行、Bean后置处理器的before/after方法、:AbstractApplicationContext#refresh#finishBeanFactoryInitialization
    Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
    Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors

3、容器初始化流程

主流程开始=> new ClassPathXmlApplicationContext(“”)=> setConfigLocations(设置本地配置信息)
image.png
=>refresh() 方法进行加锁
image.png
锁用于容器刷新和 关闭 防止刷新过程中关闭容器
image.png
prepareRefresh() 刷新前的预处理 表示自真正做refresh操作之前需要准备做的事情:如设置Spring 容器的启动时间,开启活跃状态,撤销关闭状态 验证环境信息里的一些必须存在的属性等。
=> obtainFreshBeanFactory() 主流程
image.png
此处可分为两个主要子流程:
(1)获取BeanFactory默认实现是DefaultListableBeanFactory,
(2)加载BeanDefition,并注册到BeanDefitionRegistry(此为一个Map)
obtainFreshBeanFactory()-> refreshBeanFactory()此处判断是否已经存在BeanFactory 如果有
image.png
->createBeanFactory() 获取默认beanFactory 设置ID 自定义一些属性等
image.png
默认BeanFactroy为 DefaultListableBeanFactory
image.png
至此子流程一创建beafactory结束
BeanFactory创建时序图
image.png

子流程二 加载BeanDefinitions
image.pngAbstractRefreshableApplicationContext#loadBeanDefinitions() => AbstractXmlApplicationContext#loadBeanDefinitions()image.png=>AbstractBeanDefinitionReader#loadBeanDefinitions()
=>XmlBeanDefinitionReader#loadBeanDefinitions()
image.png
=>doLoadBeanDefinitions()开始执行加载解析xml文件
image.png
=>registerBeanDefinitions()注册Bean
image.png
=>DefaultBeanDefinitionDocumentReader#registerBeanDefinitions()
=>doRegisterBeanDefinitions()
image.png
=>parseBeanDefinitions()=>BeanDefinitionReaderUtils.registerBeanDefinition()
image.png
=>DefaultListableBeanFactory#registerBeanDefinition() 放到Map中完成Bean注册
image.png
BeanDefintions解析加载注册时序图
image.png

至此子流程二 xml加载解析注册成BeanDefinition完成**

主流程接上
=>invokeBeanFactoryPostPrcessors
=> registerBeanPostProcessors(此时Bean还没有初始化)
image.png
=> finishBeanFactoryInitialization 初始化剩下的bean创建流程
image.png

4、Bean创建流程

接上小节 =>refresh() =>finishBeanFactoryInitialization() 结束bean factory创建 实例化所有单例bean
=>DefaultListableBeanFactory#preInstantiateSingletons()
image.png
这里不管⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例
=>getBean()
=>AbstractBeanFactory#doGetBean()
=>AbstractAutowireCapableBeanFactory#createBean()
=>doCreateBean() 开始创建Bean
image.png
后续给Bean填充属性,调⽤初始化⽅法,应⽤BeanPostProcessor后置处理器
image.png
在initializeBean中 分别调用后置处理器方法和init-method方法
image.png

5、lazy-init 延迟加载机制

被lazy-init=true修饰的 bean 则是在从容器⾥ 第⼀次进⾏context.getBean() 时进⾏触发。Spring 启动的时候会把所有bean信息(包括XML和注解)解 析转化成Spring能够识别的BeanDefifinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个 BeanDefifinition 进⾏处理。如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。
在DefaultListableBeanFactory#preInstantiateSingletons()判断Bean是否为懒加载
image.png

懒加载时 context.getBean(“beanName”) 才会进行第一次注入 最终会调用AbstractBeanFactory#getBean(java.lang.String) 后续流程与单例Bean基本相同。对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经初始化完成并缓存了起来。

6、IoC循环依赖问题

Spring中循环依赖场景有:
构造器的循环依赖(构造器注⼊)
Field 属性的循环依赖(set注⼊)

无法解决的循环依赖如下:
单例 bean 构造器参数循环依赖(⽆法解决)
prototype 原型 bean循环依赖(⽆法解决)
对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx⽅法产⽣循环依赖,Spring都 会直接报错处理。即 Spring 不⽀持原型 bean 的循环依赖。

Spring能解决的循环依赖为:单例bean通过setXxx或者@Autowired进⾏循环依赖。

三级缓存机制
一级缓存:单例池 二级缓存:early 三级缓存:singletonFactory
解决循环依赖步骤
image.png

一二三级缓存数据结构
singletonObjects 一级换单例池
earlySingletonObjects 二级缓存 提前暴露且已经被某个Bean引用的的Bean
singletonFactories 三级缓存 内部为产生Bean的单例工厂
image.png
Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前
Spring通过setXxx或者@Autowired⽅法解决循环依赖其实是通过提前暴露⼀个ObjectFactory对象来完成的,简单来说ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的setClassB⽅法之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中。 Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器。
在AbstractAutowireCapableBeanFactory#doCreateBean中 先进行实例化
在此判断是否提前暴露 : 需要 单例 且允许循环依赖 且正在创建
image.png

->addSingletonFactory()加入 三级缓存
image.png
->填充属性:AbstractAutowireCapableBeanFactory#populateBean
校验属性是否循环依赖的对象 如果有 则从一级缓存开始查找,如果没有则从二级缓存查找 再次从三级缓存中查找。在三级缓存找到之后 将依赖的Bean 放入二级缓存(此时放入的可能是代理对象)。同时将bean设置为自身属性。
由于构造函数注入,Bean生成时就需要依赖对象,所以无法生成放入三级缓存提前暴露。即无法解决循环依赖

bean存储经过的路径:
有循环依赖的bean 从三级缓存->二级缓存->一级缓存 依次存入
无循环依赖的bean 从三级缓存->一级缓存 不经过二级缓存

??为何需要三级缓存才能解决循环依赖?
在创建依赖对象时由于AOP 的存在,需要生成原对象的代理对象,
=>AOP存在 需要生成代理对象,遍历Bean的后置处理器(beanPostProcessors) , 判断是否有需要增强的切面,如果有则执行后置处理器image.png
=>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
后置处理器中调用wrapIfNecessary()判断是否要包装原始bean和返回代理对象
image.pngAbstractAutoProxyCreator#wrapIfNecessary
通过原始对象生成相应的代理对象
image.png
获取到代理对象后 将其存入到二级缓存并且将原始对象从三级缓存中移除,之后如果有其他的bean依赖时,直接存二级缓存中取即可,保证bean的单例,而不能直接从三级缓存中取原始对象了 否则还会检测是否需要进行增强 再次生产代理对象,违反了单例模式
image.png

三、Spring AOP源码分析

1、代理对象创建

非延迟加载 单例 Bean在容器初始化完成之后代理对象有没有产生?
image.png
在容器初始化后已经产生了 如上图所示 该代理对象是通过CGLIB代理产生。CGLIB代理对象生成需要用到原始对象。
通过上节IoC容器初始化源码分析中我们知道初始化Bean非懒加载Bean的方法为AbstractApplicationContext#refresh => #finishBeanFactoryInitialization
image.png
=>最终会进入创建Bean方法AbstractAutowireCapableBeanFactory#doCreateBean=>createBeanInstance
image.png
=>原始Bean对象产生以后 开始填充属性 做后置处AbstractAutowireCapableBeanFactory#initializeBean()
image.png
=> 调用后置处理器after方法 applyBeanPostProcessorsAfterInitialization
image.png
=>在applyBeanPostProcessorsAfterInitialization中 循环获取Bean后置处理器方法然后调用,找到切面相关代理类方法
=>AspectJAwareAdvisorAutoProxyCreator#postProcessAfterInitialization
此处AspectJAwareAdvisorAutoProxyCreator 为抽象类 AbstractAutoProxyCreator 的一个子类
image.png
=>wrapIfNecessary() 判断是否需要包装,在此 检查下缓存中该类是否已经暴露过了(可能已经创建了,⽐如A依赖B时,创建A时候,就会先去创建B。 当真正需要创建B时,就没必要再代理⼀次已经代理过的对象),避免重复创建
image.png
判断获取当前Bean相关的增强
image.png
=>如果有相关的增强 进入创建代理方法 createProxy,创建代理工厂 进行代理对象的创建
image.png
然后合并通用拦截器对象和增强 此处通过合并的方式赋予代理对象完整的功能
image.png
=>准备工作完成 开始创建代理ProxyFactory#getProxy(java.lang.ClassLoader)
image.png
在创建代理之前,先创建AOP代理工厂 通过aop代理工厂再去创建代理, 即⽤AopProxyFactory创建AopProxy, 再⽤AopProxy创建代理对象,这⾥的AopProxyFactory默认是DefaultAopProxyFactory,分析其createAopProxy⽅法
image.png
在DefaultAopProxyFactory#createAopProxy中判断使用CGLIB代理还是JDK动态代理
image.png
1、判断是否设置目标代理类 是否有指定代理接口
2、判断目标是否为接口 或者判断代理对象是否为代理类
从使⽤⽅⾯使⽤来说:设置proxyTargetClass=true强制使⽤Cglib 代理,什么参数都不设并且对象类实现了接⼝则默认⽤JDK 代理,如果没有实现接⼝则也必须⽤Cglib
=>CglibAopProxy#getProxy(java.lang.ClassLoader) 通过CGLIB创建代理对象image.png
由此可得出,Bean aop代理对象在Bean后置处理器中通过代理工厂进行代理对象的创建

2、声明式事务控制分析

注解分析:
@EnableTransactionManagement
image.png
@EnableTransactionManagement 注解使⽤ @Import 标签引⼊了
TransactionManagementConfifigurationSelector类,这个类⼜向容器中导⼊了两个重要的组件
AutoProxyRegistrar和ProxyTransactionManagementConfiguration
image.png
(1)AutoProxyRegistrar
AutoProxyRegistrar 类的 registerBeanDefifinitions ⽅法中⼜注册了⼀个组件
image.png
=> AopConfifigUtils.registerAutoProxyCreatorIfNecessary ⽅法
image.png
=>注册InfrastructureAdvisorAutoProxyCreator 其继承抽象类AbstractAdvisorAutoProxyCreator 通过代理对象创建分析 知道此抽象类是Bean的后置处理器,即在此注册了一个后置处理器的子类,用于Bean初始化时使用
image.png

(2)ProxyTransactionManagementConfiguration
它是一个添加了configuration的配置类
image.png
其注册了如下Bean
a. 返回事务增强器
image.png
属性解析器:AnnotationTransactionAttributeSource
image.png
其内部持有了一个解析器集合Set<_TransactionAnnotationParser_>
image.png
解析器具体实现为:SpringTransactionAnnotationParserimage.png
其内部方法parseTransactionAnnotation用来解析@Transaction事务属性
image.png

事务拦截器:
TransactionInterceptor实现了MethodInterceptor(通用拦截器)
该通用拦截会在产生代理对象之前和aop增强合并(上述代理对象产生中的一步),最终一起影响到代理对象。
调用该类中的invoke方法中 invokeWithinTransaction 会触发原有业务逻辑调用,增强事务
image.png
上述组件如何关联关系
事务拦截器实现了MethodInterceptor接⼝,追溯⼀下上⾯提到的 InfrastructureAdvisorAutoProxyCreator后置处理器,它会在代理对象执⾏⽬标⽅法的时候获取其拦截器链,⽽拦截器链就是这个TransactionInterceptor,这就把这两个组件联系起
来;
构造⽅法传⼊PlatformTransactionManager(事务管理器)、TransactionAttributeSource(属性解析器),但是追溯⼀下上⾯贴的ProxyTransactionManagementConfifiguration的源码,在注册事务拦截器的时候并没有调⽤这个带参构造⽅法,⽽是调⽤的⽆参构造⽅法,然后再调⽤set⽅法注⼊这两个属性,效果⼀样。
在invokeWithinTransaction 先进行获取属性解析器和事务管理器
image.png
进行事务操作,如有异常 就进行回滚 然后抛出异常。
image.png