一、Spring 源码运行环境安装
环境版本: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接口:
“&”前缀加名称可获取到FactoryBean(Bean工厂用于创建Bean)实例
BeanFactory 继承体系,不同的继承层级 具有不同的功能
ResourceLoader->加载资源
MessageSource->国际化支持
ListableBeanFactory->获取Bean集合接口工厂
HierarchicalBeanFactroy->获取父工厂
Spring将Bean相关接口 按功能进行分开定义接口,在使用时需要什么功能只需要继承相应的接口即可
2、Bean生命周期特殊时机点
(1)构造器方法(LagouBean())执行、
初始化方法(InitializingBean)执行
调用的是同一个类中相同的方法
AbstractApplicationContext #refresh=> #finishBeanFactoryInitialization(构造器/初始化方法执行)
(2)Bean工厂后置处理器初始化、方法执行
BeanFactory初始化执行:
构造初始化堆栈调用信息
后置处理器内方法执行
方法执行堆栈调用信息:
AbstractApplicationContext #refresh => #invokeBeanFactoryPostProcessors
(3)Bean后置处理器
Bean后置处理器构造器执行
对应堆栈调用信息: AbstractApplicationContext #refresh => #registerBeanPostProcessors
Bean后置处理器前初始化方法
调用堆栈信息:AbstractApplicationContext #refresh => #finishBeanFactoryInitialzation (同构造器和初始化方法)
后初始化方法执行
调用堆栈信息:AbstractApplicationContext #refresh => #finishBeanFactoryInitialzation (同构造器和初始化方法)
- 构造器执行、初始化方法执行、Bean后置处理器的before/after方法、:AbstractApplicationContext#refresh#finishBeanFactoryInitialization
Bean工厂后置处理器初始化、方法执行:AbstractApplicationContext#refresh#invokeBeanFactoryPostProcessors
Bean后置处理器初始化:AbstractApplicationContext#refresh#registerBeanPostProcessors
3、容器初始化流程
主流程开始=> new ClassPathXmlApplicationContext(“”)=> setConfigLocations(设置本地配置信息)
=>refresh() 方法进行加锁
锁用于容器刷新和 关闭 防止刷新过程中关闭容器
prepareRefresh() 刷新前的预处理 表示自真正做refresh操作之前需要准备做的事情:如设置Spring 容器的启动时间,开启活跃状态,撤销关闭状态 验证环境信息里的一些必须存在的属性等。
=> obtainFreshBeanFactory() 主流程
此处可分为两个主要子流程:
(1)获取BeanFactory默认实现是DefaultListableBeanFactory,
(2)加载BeanDefition,并注册到BeanDefitionRegistry(此为一个Map)
obtainFreshBeanFactory()-> refreshBeanFactory()此处判断是否已经存在BeanFactory 如果有
->createBeanFactory() 获取默认beanFactory 设置ID 自定义一些属性等
默认BeanFactroy为 DefaultListableBeanFactory
至此子流程一创建beafactory结束
BeanFactory创建时序图
子流程二 加载BeanDefinitions
AbstractRefreshableApplicationContext#loadBeanDefinitions() => AbstractXmlApplicationContext#loadBeanDefinitions()=>AbstractBeanDefinitionReader#loadBeanDefinitions()
=>XmlBeanDefinitionReader#loadBeanDefinitions()
=>doLoadBeanDefinitions()开始执行加载解析xml文件
=>registerBeanDefinitions()注册Bean
=>DefaultBeanDefinitionDocumentReader#registerBeanDefinitions()
=>doRegisterBeanDefinitions()
=>parseBeanDefinitions()=>BeanDefinitionReaderUtils.registerBeanDefinition()
=>DefaultListableBeanFactory#registerBeanDefinition() 放到Map中完成Bean注册
BeanDefintions解析加载注册时序图
至此子流程二 xml加载解析注册成BeanDefinition完成**
主流程接上
=>invokeBeanFactoryPostPrcessors
=> registerBeanPostProcessors(此时Bean还没有初始化)
=> finishBeanFactoryInitialization 初始化剩下的bean创建流程
4、Bean创建流程
接上小节 =>refresh() =>finishBeanFactoryInitialization() 结束bean factory创建 实例化所有单例bean
=>DefaultListableBeanFactory#preInstantiateSingletons()
这里不管⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例
=>getBean()
=>AbstractBeanFactory#doGetBean()
=>AbstractAutowireCapableBeanFactory#createBean()
=>doCreateBean() 开始创建Bean
后续给Bean填充属性,调⽤初始化⽅法,应⽤BeanPostProcessor后置处理器
在initializeBean中 分别调用后置处理器方法和init-method方法
5、lazy-init 延迟加载机制
被lazy-init=true修饰的 bean 则是在从容器⾥ 第⼀次进⾏context.getBean() 时进⾏触发。Spring 启动的时候会把所有bean信息(包括XML和注解)解 析转化成Spring能够识别的BeanDefifinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个 BeanDefifinition 进⾏处理。如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。
在DefaultListableBeanFactory#preInstantiateSingletons()判断Bean是否为懒加载
懒加载时 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
解决循环依赖步骤
一二三级缓存数据结构
singletonObjects 一级换单例池
earlySingletonObjects 二级缓存 提前暴露且已经被某个Bean引用的的Bean
singletonFactories 三级缓存 内部为产生Bean的单例工厂
Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前
Spring通过setXxx或者@Autowired⽅法解决循环依赖其实是通过提前暴露⼀个ObjectFactory对象来完成的,简单来说ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的setClassB⽅法之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中。 Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器。
在AbstractAutowireCapableBeanFactory#doCreateBean中 先进行实例化
在此判断是否提前暴露 : 需要 单例 且允许循环依赖 且正在创建
->addSingletonFactory()加入 三级缓存
->填充属性:AbstractAutowireCapableBeanFactory#populateBean
校验属性是否循环依赖的对象 如果有 则从一级缓存开始查找,如果没有则从二级缓存查找 再次从三级缓存中查找。在三级缓存找到之后 将依赖的Bean 放入二级缓存(此时放入的可能是代理对象)。同时将bean设置为自身属性。
由于构造函数注入,Bean生成时就需要依赖对象,所以无法生成放入三级缓存提前暴露。即无法解决循环依赖
bean存储经过的路径:
有循环依赖的bean 从三级缓存->二级缓存->一级缓存 依次存入
无循环依赖的bean 从三级缓存->一级缓存 不经过二级缓存
??为何需要三级缓存才能解决循环依赖?
在创建依赖对象时由于AOP 的存在,需要生成原对象的代理对象,
=>AOP存在 需要生成代理对象,遍历Bean的后置处理器(beanPostProcessors) , 判断是否有需要增强的切面,如果有则执行后置处理器
=>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
后置处理器中调用wrapIfNecessary()判断是否要包装原始bean和返回代理对象
AbstractAutoProxyCreator#wrapIfNecessary
通过原始对象生成相应的代理对象
获取到代理对象后 将其存入到二级缓存并且将原始对象从三级缓存中移除,之后如果有其他的bean依赖时,直接存二级缓存中取即可,保证bean的单例,而不能直接从三级缓存中取原始对象了 否则还会检测是否需要进行增强 再次生产代理对象,违反了单例模式
三、Spring AOP源码分析
1、代理对象创建
非延迟加载 单例 Bean在容器初始化完成之后代理对象有没有产生?
在容器初始化后已经产生了 如上图所示 该代理对象是通过CGLIB代理产生。CGLIB代理对象生成需要用到原始对象。
通过上节IoC容器初始化源码分析中我们知道初始化Bean非懒加载Bean的方法为AbstractApplicationContext#refresh => #finishBeanFactoryInitialization
=>最终会进入创建Bean方法AbstractAutowireCapableBeanFactory#doCreateBean=>createBeanInstance
=>原始Bean对象产生以后 开始填充属性 做后置处AbstractAutowireCapableBeanFactory#initializeBean()
=> 调用后置处理器after方法 applyBeanPostProcessorsAfterInitialization
=>在applyBeanPostProcessorsAfterInitialization中 循环获取Bean后置处理器方法然后调用,找到切面相关代理类方法
=>AspectJAwareAdvisorAutoProxyCreator#postProcessAfterInitialization
此处AspectJAwareAdvisorAutoProxyCreator 为抽象类 AbstractAutoProxyCreator 的一个子类
=>wrapIfNecessary() 判断是否需要包装,在此 检查下缓存中该类是否已经暴露过了(可能已经创建了,⽐如A依赖B时,创建A时候,就会先去创建B。 当真正需要创建B时,就没必要再代理⼀次已经代理过的对象),避免重复创建
判断获取当前Bean相关的增强
=>如果有相关的增强 进入创建代理方法 createProxy,创建代理工厂 进行代理对象的创建
然后合并通用拦截器对象和增强 此处通过合并的方式赋予代理对象完整的功能
=>准备工作完成 开始创建代理ProxyFactory#getProxy(java.lang.ClassLoader)
在创建代理之前,先创建AOP代理工厂 通过aop代理工厂再去创建代理, 即⽤AopProxyFactory创建AopProxy, 再⽤AopProxy创建代理对象,这⾥的AopProxyFactory默认是DefaultAopProxyFactory,分析其createAopProxy⽅法
在DefaultAopProxyFactory#createAopProxy中判断使用CGLIB代理还是JDK动态代理
1、判断是否设置目标代理类 是否有指定代理接口
2、判断目标是否为接口 或者判断代理对象是否为代理类
从使⽤⽅⾯使⽤来说:设置proxyTargetClass=true强制使⽤Cglib 代理,什么参数都不设并且对象类实现了接⼝则默认⽤JDK 代理,如果没有实现接⼝则也必须⽤Cglib
=>CglibAopProxy#getProxy(java.lang.ClassLoader) 通过CGLIB创建代理对象
由此可得出,Bean aop代理对象在Bean后置处理器中通过代理工厂进行代理对象的创建
2、声明式事务控制分析
注解分析:
@EnableTransactionManagement
@EnableTransactionManagement 注解使⽤ @Import 标签引⼊了
TransactionManagementConfifigurationSelector类,这个类⼜向容器中导⼊了两个重要的组件
AutoProxyRegistrar和ProxyTransactionManagementConfiguration
(1)AutoProxyRegistrar
AutoProxyRegistrar 类的 registerBeanDefifinitions ⽅法中⼜注册了⼀个组件
=> AopConfifigUtils.registerAutoProxyCreatorIfNecessary ⽅法
=>注册InfrastructureAdvisorAutoProxyCreator 其继承抽象类AbstractAdvisorAutoProxyCreator 通过代理对象创建分析 知道此抽象类是Bean的后置处理器,即在此注册了一个后置处理器的子类,用于Bean初始化时使用
(2)ProxyTransactionManagementConfiguration
它是一个添加了configuration的配置类
其注册了如下Bean
a. 返回事务增强器
属性解析器:AnnotationTransactionAttributeSource
其内部持有了一个解析器集合Set<_TransactionAnnotationParser_>
解析器具体实现为:SpringTransactionAnnotationParser
其内部方法parseTransactionAnnotation用来解析@Transaction事务属性
事务拦截器:
TransactionInterceptor实现了MethodInterceptor(通用拦截器)
该通用拦截会在产生代理对象之前和aop增强合并(上述代理对象产生中的一步),最终一起影响到代理对象。
调用该类中的invoke方法中 invokeWithinTransaction 会触发原有业务逻辑调用,增强事务
上述组件如何关联关系
事务拦截器实现了MethodInterceptor接⼝,追溯⼀下上⾯提到的 InfrastructureAdvisorAutoProxyCreator后置处理器,它会在代理对象执⾏⽬标⽅法的时候获取其拦截器链,⽽拦截器链就是这个TransactionInterceptor,这就把这两个组件联系起
来;
构造⽅法传⼊PlatformTransactionManager(事务管理器)、TransactionAttributeSource(属性解析器),但是追溯⼀下上⾯贴的ProxyTransactionManagementConfifiguration的源码,在注册事务拦截器的时候并没有调⽤这个带参构造⽅法,⽽是调⽤的⽆参构造⽅法,然后再调⽤set⽅法注⼊这两个属性,效果⼀样。
在invokeWithinTransaction 先进行获取属性解析器和事务管理器
进行事务操作,如有异常 就进行回滚 然后抛出异常。