Spring源码手写篇-手写IoC
一、IoC分析
1.Spring的核心
** ** **在Spring中非常核心的内容是 **IOC
和 AOP
.
2.IoC的几个疑问?
2.1 IoC是什么?
** ** IoC:Inversion of Control 控制反转,简单理解就是:依赖对象的获得被反转了。
2.2 IoC有什么好处?
IoC带来的好处:
- 代码更加简洁,不需要去new 要使用的对象了
- 面向接口编程,使用者与具体类,解耦,易扩展、替换实现者
- 可以方便进行AOP编程
2.3 IoC容器做了什么工作?
** ** IoC容器的工作:负责创建,管理类实例,向使用者提供实例。
2.4 IoC容器是否是工厂模式的实例?
** ** 是的,IoC容器负责来创建类实例对象,需要从IoC容器中get获取。IoC容器我们也称为Bean工厂。
** ** 那么我们一直说的Bean是什么呢?bean:组件,也就是类的对象!!!
二、IoC实现
** ** 通过上面的介绍我们也清楚了IoC的核心就是Bean工厂,那么这个Bean工厂我们应该要如何来设计实现它呢?我们来继续分析。
1.Bean工厂的作用
** ** 首先Bean工厂的作用我们上面也分析了就是创建,管理Bean,并且需要对外提供Bean的实例。
2.Bean工厂的初步设计
** ** 基于Bean工厂的基本作用,我们可以来分析Bean工厂应该具备的相关行为。
** ** 首先Bean工厂应该要对外提供获取bean实例的方法,所以需要定义一个getBean()方法。同时工厂需要知道生产的bean的类型,所以getBean()方法需要接受对应的参数,同时返回类型这块也可能有多个类型,我们就用Object来表示。这样Bean工厂的定义就出来了。
** ** 上面定义了Bean工厂对外提供bean实例的方法,但是Bean工厂如何知道要创建上面对象,怎么创建该对象呢?
** ** 所以在这里我们得把Bean的定义信息告诉BeanFactory工厂,然后BeanFactory工厂根据Bean的定义信息来生成对应的bean实例对象。所以在这儿我们要考虑两个问题
- 我们需要定义一个模型来表示该如何创建Bean实例的信息,也就是Bean定义。
- Bean工厂需要提供行为来接收这些Bean的定义信息。
3.Bean的定义
** ** 根据上面的接收我们就清楚了Bean定义的意义了。那么我们来定义Bean定义的模型要考虑几个问题。
3.1 Bean定义的作用是什么?
** ** 作用肯定是告诉Bean工厂应该如何来创建某类的Bean实例
3.2 获取实例的方式有哪些?
3.3 我们需要在BeanDefinition中给Bean工厂提供哪些信息?
这样一来我们就清楚了BeanDefinition应该要具有的基本功能了。
3.4 增强功能要求
** ** 当然我们可以在现有的基础上增强要求,比如Bean工厂创建的是单例对象,具有特定的初始化方法和销毁逻辑的方法。
** ** 同时创建BeanDefinition的一个通用实现类:GenericBeanDefinition。
具体代码为:
/**
* bean定义接口
*/
public interface BeanDefinition {
String SCOPE_SINGLETION = "singleton";
String SCOPE_PROTOTYPE = "prototype";
/**
* 类
*/
Class<?> getBeanClass();
/**
* Scope
*/
String getScope();
/**
* 是否单例
*/
boolean isSingleton();
/**
* 是否原型
*/
boolean isPrototype();
/**
* 工厂bean名
*/
String getFactoryBeanName();
/**
* 工厂方法名
*/
String getFactoryMethodName();
/**
* 初始化方法
*/
String getInitMethodName();
/**
* 销毁方法
*/
String getDestroyMethodName();
boolean isPrimary();
/**
* 校验bean定义的合法性
*/
default boolean validate() {
// 没定义class,工厂bean或工厂方法没指定,则不合法。
if (this.getBeanClass() == null) {
if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
return false;
}
}
// 定义了类,又定义工厂bean,不合法
if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
return false;
}
return true;
}
}
4.Bean的注册
** ** Bean的定义清楚后,我们要考虑的就是如何实现BeanDefinition和BeanFactory的关联了。
** ** **在这儿我们可以专门定义一个 **BeanDefinitionRegistry
来实现Bean定义的注册功能。
** ** 那么我们需要考虑 BeanDefinitionRegistry 应该具备的功能,其实也简单就两个:
- 注册BeanDefinition
- 获取BeanDefinition
** ** 同时为了保证能够区分每个BeanDefinition的定义信息,我们得给每一个Bean定义一个唯一的名称。
具体实现代码:
public interface BeanDefinitionRegistry {
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionRegistException;
BeanDefinition getBeanDefinition(String beanName);
boolean containsBeanDefinition(String beanName);
}
5.BeanFactory实现
** ** 到现在为止我们来看看已经实现的相关设计功能:
** ** 通过上面的分析我们接下来就要考虑BeanFactory的功能实现了。我们先来实现一个最基础的默认的Bean工厂:DefaultBeanFactory。需要DefaultBeanFactory实现如下的5个功能
- 实现Bean定义信息的注册
- 实现Bean工厂定义的getBean方法
- 实现初始化方法的执行
- 实现单例的要求
- 实现容器关闭是执行单例的销毁操作
具体看代码的案例代码,代码太多就不贴出来了。
思考:对于单例bean,我们可否提前实例化?
三、IoC增强
** ** 上面第一版本的IoC容器我们已经实现了,我们可以在这个基础上来基础迭代增强IoC的功能
1.Bean别名的增强
** ** Bean除了标识唯一的名称外,还可以有任意个别名,别名也是唯一的。别名的特点
- 可以有多个别名
- 也可以是别名的别名
- 别名也是唯一的
** ** ** **实现的时候我们需要考虑的问题
- 数据结构
- 功能点
具体代码交给大家课后尝试实现。
2. Type类型的增强
** ** **上面实现的是根据 bean的 **name
来获取Bean实例,我们还希望能扩展通过 Type
来获取实例对象。这时对应的接口为:
** ** 也就是需要实现根据Type找到Bean对象的功能。正常的实例逻辑为:
** ** 但是上面的实现方案有点吃性能,我们可以尝试优化下,我们可以提前把Type和Bean的对应关系找出来,然后用Map缓存起来处理。对应的存储方式通过Map来处理
我们需要考虑几个问题:
- Map中存储的数据用什么合适?
- type和bean是一对一的关系吗?
- 何时建立该关系呢?
private Map<Class<?>, Set<String>> typeMap = new ConcurrentHashMap<>(256);
** ** 具体的实现我们可以在DefaultBeanFactory中添加一个buildTypeMap()方法来处理这个事情
** ** buildTypeMap()方法处理的逻辑如下:
** ** 然后我们在BeanFactory中添加一个getType方法,封装获取Bean的Type的逻辑,方便buildTypeMap()方法的使用。最后就是getBean(Class
IoC容器-核心部分类图
总结:应用设计的原则:
- 抽象,行为抽象分类处理(接口)
- 继承,扩展功能
- 面向接口编程
- 单一职责原则
Spring源码手写篇-手写DI
** ** 简单回顾前面的手写IoC的内容。
一、DI介绍
** ** DI(Dependency injection)依赖注入。对象之间的依赖由容器在运行期决定,即容器动态的将某个依赖注入到对象之中。说的直白点就是给Bean对象的成员变量赋值。
** ** 在这里我们就需要明白几个问题。
1. 哪些地方会有依赖
- 构造参数依赖
- 属性依赖
2. 依赖注入的本质是什么?
** ** **依赖注入的本质是 **赋值
。赋值有两种情况
- 给有参构造方法赋值
- 给属性赋值
3. 参数值、属性值有哪些?
** ** 具体赋值有两种情况:直接值和Bean依赖。比如
public clsss Girl{
public Girl(String name,int age,char cup,Boy boyfriend){
...
}
}
4. 直接赋值有哪些?
- 基本数据类型:String、int 等
- 数组,集合
- map
二、构造注入
** ** 我们先来看看构造参数注入的情况应该要如何解决。
1.构造注入分析
** ** 我们应该如何定义构造参数的依赖?也就是我们需要通过构造方法来创建实例,然后对应的构造方法我们需要传入对应的参数。如果不是通过IoC来处理,我们可以直接通过如下的代码实现。
public static void main(String[] args) {
Boy boy = new Boy();
Girl girl = new Girl("小丽",20,'C',boy);
}
** ** 我们通过直接赋值的方式就可以了。但是在IoC中我们需要通过反射的方式来处理。那么我们在通过反射操作的时候就需要能获取到对应的构造参数的依赖了,这时我们得分析怎么来存储我们的构造参数的依赖了。构造参数的依赖有两个特点:
- 数量
- 顺序
** ** 上面的例子中的参数
- 小丽
- 20
- 'C'
- boy,是一个依赖Bean
** ** 参数可以有多个,我们完全可以通过List集合来存储,而且通过添加数据的顺序来决定构造参数的顺序了。但是这里有一个问题,如何表示Bean依赖呢?直接值我们直接添加到集合中就可以了,但是Bean依赖,我们还没有创建对应的对象,这时我们可以维护一个自定义对象,来绑定相关的关系。
2. BeanReference
** ** BeanReference就是用来说明bean依赖的:也就是这个属性依赖哪个类型的Bean
** ** 可以根据name来依赖,也可以按照Type来依赖。当然我们的程序中还有一点需要考虑,就是如何来区分是直接值还是Bean依赖呢?有了上面的设计其实就很容易判断了。
if ( obj instance BeanReference)
** ** 当然还有一种比较复杂的情况如下:
** ** 直接值是数组或者集合等,同时容器中的元素是Bean依赖,针对这种情况元素值还是需要用BeanReference来处理的。Bean工厂在处理时需要遍历替换。
3. BeanDefinition实现
** ** **接下来我们看看如何具体的来实现DI基于构造参数依赖的相关操作。首先是定义的相关处理了。我们需要在 **BeanDefinition
中增加构造参数的获取的方法。
** ** 然后我们需要在默认的实现GenericBeanDefinition中增加对应的方法来处理。
** ** 定义后我们可以测试下对应的应用,定义个ABean,依赖了CBean
public class ABean {
private String name;
private CBean cb;
public ABean(String name, CBean cb) {
super();
this.name = name;
this.cb = cb;
System.out.println("调用了含有CBean参数的构造方法");
}
public ABean(String name, CCBean cb) {
super();
this.name = name;
this.cb = cb;
System.out.println("调用了含有CCBean参数的构造方法");
}
public ABean(CBean cb) {
super();
this.cb = cb;
}
public void doSomthing() {
System.out.println("Abean.doSomthing(): " + this.name + " cb.name=" + this.cb.getName());
}
public void init() {
System.out.println("ABean.init() 执行了");
}
public void destroy() {
System.out.println("ABean.destroy() 执行了");
}
}
然后在实例化时我们需要做相关的绑定
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ABean.class);
// 定义的构造参数的依赖
List<Object> args = new ArrayList<>();
args.add("abean01");
// Bean依赖 通过BeanReference 来处理
args.add(new BeanReference("cbean"));
bd.setConstructorArgumentValues(args);
bf.registerBeanDefinition("abean", bd);
**构造参数传递后,接下来其实我们就需要要在 **BeanFactory
中来实现构造参数的注入了
4.BeanFactory实现
** ** 前面我们在BeanFactory中实现Bean对象的创建有几种方式
- 构造方法创建
- 工厂静态方法
- 工厂成员方法
** ** 我们在通过构造方法创建其实是通过无参构造方法来处理的,这时我们需要改变这块的逻辑,通过有参构造方法来实现。
// 构造方法来构造对象
private Object createInstanceByConstructor(BeanDefinition bd)
throws InstantiationException, IllegalAccessException {
try {
return bd.getBeanClass().newInstance();
} catch (SecurityException e1) {
log.error("创建bean的实例异常,beanDefinition:" + bd, e1);
throw e1;
}
}
** ** 我们就需要对上面的方法做出改变。
// 构造方法来构造对象
private Object createInstanceByConstructor(BeanDefinition bd)
throws InstantiationException, IllegalAccessException {
// 1. 得到真正的参数值
List<?> constructorArgumentValues = bd.getConstructorArgumentValues();
// 2.根据对应的构造参数依赖获取到对应的 Constructor
Constructor constructor = 得到对应的构造方法
// 3.用实际参数值调用构造方法创建对应的对象
return constructor.newInstance(Object ... 实参值);
}
** ** 通过上面的分析我们需要获取对应的构造器。这块我们需要通过反射来获取了。下面是具体的实现逻辑
** ** 根据上面的分析,我们实现的逻辑分为两步
- 先根据参数的类型进行精确匹配查找,如果没有找到,继续执行第二步操作
- 获得所有的构造方法,遍历构造方法,通过参数数量过滤,再比对形参与实参的类型
** ** 因为这里有个情况,实参是Boy,构造方法的形参是Person,第一种精确匹配就没有办法关联了。
具体的实现代码如下:
private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
/*判定构造方法的逻辑应是怎样的?
1 先根据参数的类型进行精确匹配查找,如未找到,则进行第2步查找;
2获得所有的构造方法,遍历,通过参数数量过滤,再比对形参类型与实参类型。
* */
Constructor<?> ct = null;
//没有参数,则用无参构造方法
if (args == null) {
return bd.getBeanClass().getConstructor(null);
}
// 1 先根据参数的类型进行精确匹配查找
Class<?>[] paramTypes = new Class[args.length];
int j = 0;
for (Object p : args) {
paramTypes[j++] = p.getClass();
}
try {
ct = bd.getBeanClass().getConstructor(paramTypes);
} catch (Exception e) {
// 这个异常不需要处理
}
if (ct == null) {
// 2 没有精确参数类型匹配的,获得所有的构造方法,遍历,通过参数数量过滤,再比对形参类型与实参类型。
// 判断逻辑:先判断参数数量,再依次比对形参类型与实参类型
outer:
for (Constructor<?> ct0 : bd.getBeanClass().getConstructors()) {
Class<?>[] paramterTypes = ct0.getParameterTypes();
if (paramterTypes.length == args.length) { //通过参数数量过滤
for (int i = 0; i < paramterTypes.length; i++) { //再依次比对形参类型与实参类型是否匹配
if (!paramterTypes[i].isAssignableFrom(args[i].getClass())) {
continue outer; //参数类型不可赋值(不匹配),跳到外层循环,继续下一个
}
}
ct = ct0; //匹配上了
break outer;
}
}
}
if (ct != null) {
return ct;
} else {
throw new Exception("不存在对应的构造方法!" + bd);
}
}
** ** 上面我们考虑的是BeanFactory通过构造器来获取对象的逻辑,那如果我们是通过静态工厂方法或者成员工厂方法的方式来处理的,那么构造参数依赖的处理是否和前面的是一样的呢?其实是差不多的,我们需要根据对应的构造参数来推断对应的工厂方法
// 静态工厂方法
private Object createInstanceByStaticFactoryMethod(BeanDefinition bd) throws Exception {
Object[] realArgs = this.getConstructorArgumentValues(bd);
Class<?> type = bd.getBeanClass();
Method m = this.determineFactoryMethod(bd, realArgs, type);
return m.invoke(type, realArgs);
}
// 工厂bean方式来构造对象
private Object createInstanceByFactoryBean(BeanDefinition bd) throws Exception {
Object[] realArgs = this.getConstructorArgumentValues(bd);
Method m = this.determineFactoryMethod(bd, realArgs, this.getType(bd.getFactoryBeanName()));
Object factoryBean = this.doGetBean(bd.getFactoryBeanName());
return m.invoke(factoryBean, realArgs);
}
5.缓存功能
** ** 对于上面的处理过程相信大家应该清楚了,我们通过推断也得到了对应的构造方法或者对应的工厂方法,那么我们可以不可以在下次需要再次获取的时候省略掉推导的过程呢?显然我们可以在BeanDefinition中增加缓存方法可以实现这个需求。
6. 循环依赖问题
** ** 上图是循环依赖的三种情况,虽然方式有点不一样,但是循环依赖的本质是一样的,就你的完整创建要依赖与我,我的完整创建也依赖于你。相互依赖从而没法完整创建造成失败。
** ** 我们通过构造参数依赖是完全可能出现上面的情况的,那么这种情况我们能解决吗?构造依赖的情况我们是解决不了的。
public class Test01 {
public static void main(String[] args) {
new TestService1();
}
}
class TestService1{
private TestService2 testService2 = new TestService2();
}
class TestService2{
private TestService1 testService1 = new TestService1();
}
** ** 既然解决不了,那么我们在程序中如果出现了,应该要怎么来解决呢?其实我们可以在创建一个Bean的时候记录下这个Bean,当这个Bean创建完成后我们在移除这个Bean,然后我们在getBean的时候判断记录中是否有该Bean,如果有就判断为循环依赖,并抛出异常。数据结构我们可以通过Set集合来处理。
到此构造注入的实现我们就搞定了。
三、属性注入
** ** 上面搞定了构造注入的方式。接下来我们再看看属性注入的方式有什么需要注意的地方。
1. 属性依赖分析
** ** 属性依赖就是某个属性依赖某个值。
public class Girl {
private String name;
private int age;
private char cup;
private List<Boy> boyFriends;
// ....
}
** ** **那么在获取实例对象后如何根据相关的配置来给对应的属性来赋值呢?这时我们可以定义一个实体类 **PropertyValue
来记录相关的属性和值。
2.BeanDefinition实现
** ** 这时我们就需要在BeanDefinition中关联相关属性信息了。
3.BeanFactory实现
** ** 然后我们在BeanFactory的默认实现DefaultBeanFactory中实现属性值的依赖注入。
// 创建好实例对象
// 给属性依赖赋值
this.setPropertyDIValues(bd,instance);
// 执行初始化相关方法
this.doInit(bd,instance);
** ** 具体的实现代码如下:
// 给入属性依赖
private void setPropertyDIValues(BeanDefinition bd, Object instance) throws Exception {
if (CollectionUtils.isEmpty(bd.getPropertyValues())) {
return;
}
for (PropertyValue pv : bd.getPropertyValues()) {
if (StringUtils.isBlank(pv.getName())) {
continue;
}
Class<?> clazz = instance.getClass();
Field p = clazz.getDeclaredField(pv.getName());
//暴力访问 private
p.setAccessible(true);
p.set(instance, this.getOneArgumentRealValue(pv.getValue()));
}
}
4.循环依赖问题
** ** 在构造参数依赖中我们发现没有办法解决,在属性依赖中同样会存在循环依赖的问题,这时我们能解决吗?
** ** 其实这种情况我们不在IoC场景下非常好解决。如下
Boy b = new Boy();
Girl g = new Girl();
b.setGirl(g);
g.setBoy(b);
** ** 但是在IoC好像不是太好解决:
** ** **针对这种情况我们需要通过 **提前暴露
来解决这个问题,具体看代码!!!
private void doEarlyExposeBuildingBeans(String beanName, Object instance) {
Map<String,Object> earlyExposeBuildingBeansMap = earlyExposeBuildingBeans.get();
if(earlyExposeBuildingBeansMap == null) {
earlyExposeBuildingBeansMap = new HashMap<>();
earlyExposeBuildingBeans.set(earlyExposeBuildingBeansMap);
}
earlyExposeBuildingBeansMap.put(beanName,instance);
}
最后现阶段已经实现的类图结构
扩展作业:加入Bean配置的条件依赖生效的支持
在Bean定义配置中可以指定它条件依赖某些Bean或类,当这些Bean或类存在时,这个bean的配置才能生效!
Spring源码手写篇-手写AOP
** ** 手写IoC和DI后已经实现的类图结构。
一、AOP分析
1.AOP是什么?
** ** ** AOP[Aspect Oriented Programming] 面向切面编程,在不改变类的代码的情况下,对类方法进行功能的增强。**
2.我们要做什么?
** ** 我们需要在前面手写IoC,手写DI的基础上给用户提供AOP功能,让他们可以通过AOP技术实现对类方法功能增强。
3.我们的需求是什么?
** ** 提供AOP功能!,然后呢?... 没有了。关键还是得从上面的定义来理解。
二、AOP概念讲解
** ** 上面在分析AOP需求的时候,我们介绍到了相关的概念,Advice、Pointcuts和weaving等,首先我们来看看在AOP中我们会接触到的相关的概念都有哪些。
更加形象的描述
然后对于上面的相关概念,我们就要考虑哪些是用户需要提供的,哪些是框架要写好的?
思考:Advice,Pointcuts和Weaving各自的特点
三、切面实现
** ** 通过上面的分析,我们要设计实现AOP功能,其实就是要设计实现上面分析的相关概念对应的组件。
1.Advice
1.1 面向接口编程
** ** **Advice:通知,是由用户提供的,我们来使用,主要是用户提供就突出了 **多变性
。针对这块我们应该怎么设计?这里有两个问题:
- 我们如何能够识别用户提供的东西呢?用户在我们写好框架后使用我们的框架
- 如何让我们的代码隔绝用户提供的多变性呢?
针对这种情况我们定义一套标准的接口,用户通过实现接口类提供他们不同的逻辑。是否可行?
这里有个重要的设计原则大家要注意: 如何应对变化,通过面向接口编程来搞定!!!
我们先定义一个空的接口,可以先思考下我们为什么定义一个空的接口呢?
1.2 Advice的特点分析
** ** Advice的特点:可选时机,可选择在方法执行前、后、异常时进行功能的增强
结合上面的情况我们可以分析出Advice通知的几种情况
- 前置增强-Before
- 后置增强-AfterReturn
- 环绕增强-Around
- 最终通知-After
- 异常通知-Throwing
有这么多的情况我们应该要怎么来实现呢?我们可以定义标准的接口方法,让用户来实现它,提供各种具体的增强内容。那么这四种增强相关的方法定义是怎样的呢?我们一一来分析下。
1.3 各种通知分析
1.3.1 前置增强
前置增强:在方法执行前进行增强。
问题1:它可能需要的参数?
** ** 目的是对方法进行增强,应该需要的是方法相关的信息,我们使用它的时候能给如它的就是当前要执行方法的相关信息了
问题2:运行时方法有哪些信息?
- 方法本身 Method
- 方法所属的对象 Object
- 方法的参数 Object[]
问题3:前置增强的返回值是什么?
** ** 在方法执行前进行增强,不需要返回值!
public interface MethodBeforeAdvice extends Advice {
/**
* 实现该方法进行前置增强
*
* @param method
* 被增强的方法
* @param args
* 方法的参数
* @param target
* 被增强的目标对象
* @throws Throwable
*/
void before(Method method, Object[] args, Object target) throws Throwable;
}
1.3.2 最终通知
** ** 最终通知:在方法执行后进行增强
问题1:它可能需要的参数?
- 方法本身 Method
- 方法所属的对象 Object
- 方法的参数 Object[]
- 方法的返回值 Object 可能没有
问题2:它的返回值是什么?
** ** 这个就需要看是否允许在After中更改返回的结果,如果规定只可用、不可修改返回值就不需要返回值
public interface AfterAdvice extends Advice {
/**
* 实现该方法,提供后置增强
*
* @param returnValue
* 返回值
* @param method
* 被增强的方法
* @param args
* 方法的参数
* @param target
* 方法的所属对象
* @throws Throwable
*/
void after(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
1.3.3 后置通知
** ** 后置增强:在方法执行后进行增强
问题1:他可能需要的参数
- 方法本身 Method
- 方法所属的对象 Object
- 方法的参数 Object[]
- 方法的返回值 Object
问题2:它的返回值是什么?
** ** 这个就需要看是否允许在After中更改返回的结果,如果规定只可用、不可修改返回值就不需要返回值
public interface AfterReturningAdvice extends Advice {
/**
* 实现该方法,提供AfterRetun增强
*
* @param returnValue
* 返回值
* @param method
* 被增强的方法
* @param args
* 方法的参数
* @param target
* 方法的所属对象
* @throws Throwable
*/
void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;
}
1.3.4 环绕通知
Around环绕增强:包裹方法进行增强
问题1:他可能需要的参数
- 方法本身 Method
- 方法所属的对象 Object
- 方法的参数 Object[]
问题2:它的返回值是面试?
** ** 方法被它包裹,即方法将由它来执行,它需要返回方法的返回值
public interface MethodInterceptor extends Advice {
/**
* 对方法进行环绕(前置、后置)增强、异常处理增强,方法实现中需调用目标方法。
*
* @param method
* 被增强的方法
* @param args
* 方法的参数
* @param target
* 方法所属对象
* @return Object 返回值
* @throws Throwable
*/
Object invoke(Method method, Object[] args, Object target) throws Throwable;
}
1.3.5 异常通知
异常通知增强:对方法执行时的异常,进行增强处理
问题1:它可能需要什么参数?
- 一定需要Exception
- 可能需要方法本身 Method
- 可能需要方法所属的对象 Object
- 可能需要方法的参数 Object[]
问题2:它的返回值是什么?
** ** 这个就需要看是否允许在After中更改返回的结果,如果规定只可用、不可修改返回值就不需要返回值
public interface ThrowsAdvice extends Advice {
void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable;
}
1.4 Advice设计
** ** 结合上面的分析,我们就可以得出Advice的体系图了
2.Pointcut
2.1 Pointcut的特点有:
- 用户性:由用户指定
- 变化性:用户可灵活指定
- 多点性:用户可以选择在多个点上进行增强
2.2 Pointcut分析
** ** 为用户提供一个东西,让他们可以灵活地指定多个方法点,而且我们还能看懂!
思考:切入点是由用户来指定在哪些方法点上进行增强,那么这个哪些方法点如何来表示能满足上面的需求呢?
分析:
- 指定哪些方法,是不是一个描述信息?
- 如何来指定一个方法?
- 如果有重载的情况怎么办?
- 123要求的其实就是一个完整的方法签名
com.boge.spring.aop.Girl.dbj(Boy,Time)
com.boge.spring.aop.Girl.dbj(Boy,Girl,Time)
我们还得进一步分析:如何做到多点性和灵活性,在一个描述中指定一类类的某些方法?
- 某个包下的某个类的某个方法
- 某个包下的所有类中的所有方法
- 某个包下的所有类中的do开头的方法
- 某个包下的以service结尾的类中的do开头的方法
- .....
也就是我们需要有这样一个表达式能够灵活的描述上面的这些信息。
这个表达式表达的内容有:
而且每个部分的要求是怎么样的呢?
- 包名:有父子特点,要能模糊匹配
- 类名:要能模糊匹配
- 方法名:要能模糊匹配
- 参数类型:参数可以有多个
那么我们设计的这个表达式将被我们用来决定是否需要对某个类的某个方法进行增强,这个决定过程应该是怎么样的?
针对需求我们的选择是:
AspectJ官网:http://www.eclipse.org/aspectj
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。注意,表达式中加[ ]的部分表示可省略部分,各部分间用空格分开。在其中可以使用以下符号
举例:
execution(public * (. .)) 指定切入点为:任意公共方法。 execution( set (. .)) 指定切入点为:任何一个以“set”开始的方法。 *execution( com.xyz.service..*(. .)) 指定切入点为:定义在service包里的任意类的任意方法。 execution(* com.xyz.service. ..(. .)) 指定切入点为:定义在service包或者子包里的任意类的任意方法。“..”出现在类名中时, 后面必须跟“*”,表示包、子包下的所有类。 execution( .service..*(. .))* 指定只有一级包下的serivce子包下所有类(接口)中的所有方法为切入点 execution( . .service..*(. .))* **指定所有包下的serivce子包下所有类(接口)中的所有方法为切入点
2.3 Pointcut设计
** ** 通过分析完成我们就该对Pointcut类设计了,接口,类。
思考1:首先考虑切入点应该具有的属性--->切入点表达式
思考2:切入点应对外提供什么行为
思考3:切入点被我们设计用来做什么?
** ** 对类和方法进行匹配,切入点应该提供匹配类,匹配方法的行为
思考4:如果在我们设计的框架中要能灵活的扩展切点,我们应该如何设计?
** ** 这又是一个要支持可多变的问题,像通知一样,我们定义一套标准接口,定义好基本行为,面向接口编程,屏蔽掉具体的实现。不管哪些方案,都实现匹配类,匹配方法的接口。
案例代码
public interface Pointcut {
boolean matchsClass(Class<?> targetClass);
boolean matchsMethod(Method method, Class<?> targetClass);
}
然后来看看AspectJ的实现
案例代码
public class AspectJExpressionPointcut implements Pointcut {
private static PointcutParser pp = PointcutParser
.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
private String expression;
private PointcutExpression pe;
public AspectJExpressionPointcut(String expression) {
super();
this.expression = expression;
pe = pp.parsePointcutExpression(expression);
}
@Override
public boolean matchsClass(Class<?> targetClass) {
return pe.couldMatchJoinPointsInType(targetClass);
}
@Override
public boolean matchsMethod(Method method, Class<?> targetClass) {
ShadowMatch sm = pe.matchesMethodExecution(method);
return sm.alwaysMatches();
}
public String getExpression() {
return expression;
}
}
3.切面Aspect
搞定了两个难点后,我们来看看用户该如何使用我们提供的东西
为此我们需要创建对应的接口来管理。
4. Advisor
为用户提供更简单的外观,Advisor(通知者)组合Advice和Pointcut。
当然扩展的形式比较多:
或者:
四、织入实现
1. 织入的分析
** ** 织入要完成的是什么?织入其实就是要把用户提供的增强功能加到指定的方法上。
思考1:在什么时候织入?
** ** 创建Bean实例的时候,在Bean初始化后,再对其进行增强。
思考2:如何确定bean要增强?
** ** 对bean类及方法挨个匹配用户配置的切面,如果有切面匹配就是要增强
思考3:如何实现织入?
** ** 代理方式
2.织入的设计
** ** 为了更好的去设计织入的实现,先整理下AOP的使用流程。
这里我们要考虑匹配、织入逻辑写到哪里?是写在BeanFactory中吗?
这时我们要考虑如果我们直接在BeanFactory中来处理,后续如果还有其他的需求是不是也要在BeanFactory中处理呢?这样操作有什么不好的地方呢?
- BeanFactory代码爆炸,不专情
- 不易扩展
那我们应该要怎么来设计呢?
我们先来回顾下Bean的生产的过程
在这个过程中, 将来会有更多处理逻辑加入到Bean生产过程的不同阶段。我们现在最好是设计出能让我们后面不用再改BeanFactory的代码就能灵活的扩展。
这时我们可以考虑用观察者模式,通过在各个节点加入扩展点,加入注册机制。
那么在这块我们就应用观察者模式来加入一个Bean的后置处理器 BeanPostProcessor
具体的我们在代码中来看看。
3.织入的实现
3.1 分析
** ** 我们先定义了 BeanPostProcessor 接口,在这个接口中我们定义了相关的行为,也就是初始化之前和初始化之后要执行的方法。
** ** 那么在此处我们需要在BeanFactory对创建的Bean对象做初始化前后要校验是否需要做相关的增强操作。
** ** 在BeanFactory中我们提供了BeanPostProcessor的注册方法。
那么结合BeanFactory要实现相关的Bean增强操作,我们要做的行为就是两方面
- 创建相关的BeanPostProcessor,并注册到BeanFactory中
- BeanFactory在初始化Bean前后判断是否有相关BeanPostProcessor,如果有做相关的增强处理
** ** 有了上面的分析,那么我们要实现具体的织入就需要来看看在对应前置和后置方法中我们要实现的功能
3.2 判断是否需要增强
** ** 我们如何判断Bean对象是否需要增强呢?其实就是需要判断该Bean是否满足用户定义的切入点表达式。也就是我们需要简单Bean所属的类和所有方法。然后遍历Advisor。取出advisor中的Pointcut来匹配类和方法。
代码层面
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws Throwable {
/*逻辑
1 判断Bean是否需要增强
2 创建代理来实现增强
*/
//1 判断Bean是否需要增强
List<Advisor> matchAdvisors = getMatchedAdvisors(bean, beanName);
// 2如有切面切中,创建代理来实现增强
if (CollectionUtils.isNotEmpty(matchAdvisors)) {
bean = this.createProxy(bean, beanName, matchAdvisors);
}
return bean;
}
3.3 代理对象
** ** 通过上面的分析如果Bean需要被增强,那么我们就需要创建Bean对应的代理对象了。代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在调用者和目标对象之间起到中介的作用;
** ** 动态代理的实现方法有哪些?
JDK动态代理:
在运行时,对接口创建代理对象
cglib动态代理:
3.4 代理实现层设计
** ** **动态代理的实现方式有很多种,如何能够做到灵活的扩展呢?在这里我们同样可以通过 **抽象
和 面向接口编程
来设计一套支持不同代理实现的代码
** ** 有了上面的设计,然后就是需要考虑代理对象的创建了。
3.5 增强逻辑实现
** ** 代理对象搞定后我们需要考虑核心的问题就是怎么来实现我们要增强的逻辑呢?首先不管你用哪种方式来生成代理对象最终增强的逻辑代码是一样的。所以我们可以把这部分内容提炼出来。
** ** 然后具体的应用Advice增强实现的逻辑为:
注意此处用到了责任链模式
public static Object applyAdvices(Object target, Method method, Object[] args, List<Advisor> matchAdvisors,
Object proxy, BeanFactory beanFactory) throws Throwable {
// 这里要做什么? 需要获取相关案例代码的+V:boge3306 备注:手写Spring
// 1、获取要对当前方法进行增强的advice
List<Object> advices = AopProxyUtils.getShouldApplyAdvices(target.getClass(), method, matchAdvisors,
beanFactory);
// 2、如有增强的advice,责任链式增强执行
if (CollectionUtils.isEmpty(advices)) {
return method.invoke(target, args);
} else {
// 责任链式执行增强
AopAdviceChainInvocation chain = new AopAdviceChainInvocation(proxy, target, method, args, advices);
return chain.invoke();
}
}
然后我们前面的Creator要怎么使用AopProxy呢?这块我们可以通过工厂模式来处理
public interface AopProxyFactory {
AopProxy createAopProxy(Object bean, String beanName, List<Advisor> matchAdvisors, BeanFactory beanFactory)
throws Throwable;
/**
* 获得默认的AopProxyFactory实例
* 需要获取相关案例代码的+V:boge3306 备注:手写Spring
* @return AopProxyFactory
*/
static AopProxyFactory getDefaultAopProxyFactory() {
return new DefaultAopProxyFactory();
}
}
到这儿,完整的增强逻辑就梳理通了
Spring源码手写篇-Bean定义配置化
一、Bean定义配置分析
** ** 我们前面实现了手写IoC和AOP的功能,但是我们在使用的时候发现我们的调用代码还是非常的繁琐,会给应用者很不好的体验。
** ** 上面的代码很直观的看到重复代码很多,要用户设置的内容也很多,低效而且容易出错,这时我们可以看看在Spring中是怎么处理的呢?
一种是通过XML的配置文件方式
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="abean" class="com.study.spring.samples.ABean">
<constructor-arg type="String" value="abean01" />
<constructor-arg ref="cbean" />
</bean>
<bean id="cbean" class="com.study.spring.samples.CBean">
<constructor-arg type="String" value="cbean01" />
</bean>
</beans>
一种是通过注解的方式来处理
@Component
public class AController{
@Autowired
private Acc ac;
}
1. XML方式实现
基于XML方式实现我们需要做什么操作呢?
- 定义XML规范
- 要写代码来解析XML,完成Bean定义的注册
2.注解方式实现
基于XML方式实现我们需要做什么操作呢?
- 定义一套注解
- 要写代码来扫描、解析注解、完成Bean定义注册。
二、Bean定义配置实现
1. XML方法设计
** ** xml方式的流程如下:
我们可以自己写一个解析器,专门来解析对应的xml文件
2. 注解方式设计
2.1 定义相关的注解
** ** 然后我们来看看需要定义的注解有哪些。
- 类要不要配置为Bean @Component
- BeanName Scope和Primary @Scope @Primary
- 工厂方法 工厂Bean @Bean
- 初始化方法、销毁方法 @PostConstruct @PreDestory
- 构造参数依赖 @Autowired @Value
- 属性依赖 @Qualifier
2.2 扫描解析注册操作
** ** 我们定义了相关注解后,谁来实现扫描注解、解析注解并完成Bean定义注册呢
先来看如何实现扫描操作
实现的逻辑应该是递归找出包目录下的所有的.class 文件。
public void scan(String... basePackages) throws Throwable {
if (basePackages != null && basePackages.length > 0) {
for (String p : basePackages) {
/*
1 递归扫描包目录下的.class文件
2 组合包路径+class文件名 得到全限定类名
3 ClassLoad.load("类名") 得到 Class 对象
4 解析Class上的注解,获得Bean定义信息,注册Bean定义
*/
//1 递归扫描包目录下的.class文件
Set<File> classFiles = this.doScan(p);
//2 得到Class对象,并解析注解、注册Bean定义
this.readAndRegisterBeanDefintion(classFiles);
}
}
}
然后看看如何来解析类注解
private void readAndRegisterBeanDefintion(Set<File> classFiles) throws BeanDefinitionRegistException {
for (File classFile : classFiles) {
String className = getClassNameFromFile(classFile);
try {
//加载类
Class<?> clazz = this.getClass().getClassLoader().loadClass(className);
Component component = clazz.getAnnotation(Component.class);
if (component != null) {// 标注了@Component注解
String beanName = component.value();
if (StringUtils.isBlank(beanName)) {
beanName = this.generateBeanName(clazz);
}
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(clazz);
//处理Scope
Scope scope = clazz.getAnnotation(Scope.class);
if (scope != null) {
bd.setScope(scope.value());
}
//处理primary
Primary primary = clazz.getAnnotation(Primary.class);
if (primary != null) {
bd.setPrimary(true);
}
// 处理构造方法,在构造方法上找@Autowired注解,如有,将这个构造方法set到bd;
this.handleConstructor(clazz, bd);
//处理方法上的注解(找出初始化、销毁、工厂方法)
this.handleMethod(clazz, bd, beanName);
// 处理属性依赖
this.handlePropertyDi(clazz, bd);
// 注册bean定义
this.registry.registerBeanDefinition(beanName, bd);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3.ApplicationContext
** ** 通过上面的设计,我们可以实现注解的方式来定义,但是给用户的整体体验还是不是很好,这时我们可以通过外观模式,为框架定义一个更简单的统一使用界面
组合为:
Spring源码篇-ApplicationContext
** ** 前面通过手写IoC,DI、AOP和Bean的配置。到最后ApplicationContext的门面处理,对于Spring相关的核心概念应该会比较清楚了。接下来我们就看看在Spring源码中,对于的核心组件是如何实现的。
一、ApplicationContext
** ** ApplicationContext到底是什么?字面含义是应用的上下文。这块我们需要看看ApplicationContext的具体的结构。
** ** **通过ApplicationContext实现的相关接口来分析,ApplicationContext接口在具备BeanFactory的功能的基础上还扩展了 **应用事件发布
,资源加载
,环境参数
和 国际化
的能力。然后我们来看看ApplicationContext接口的实现类的情况。
** ** **在ApplicationContext的实现类中有两个比较重要的分支 **AbstractRefreshableApplicationContext
和 GenericApplicationContext
.
二、BeanFactory
** ** **上面分析了 **ApplicationContext
接口的结构。然后我们来看看 BeanFactory
在ApplicationContext中具体的实现是怎么样的
可以看到具体的实现是 DefaultListableBeanFactory .然后我们来看看他的体系结构
BeanFactory的继承体系
三、BeanDefinition
** ** 然后我们来了解下ApplicationContext是如何来加载Bean定义的。具体代码我们需要分为XML配置文件和基于注解的两种方式来看。
1.基于XML方式
** ** 我们先定义对应的application.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="beanE" class="com.study.spring.sample.config.BeanE" />
<bean id="beanF" class="com.study.spring.sample.config.BeanF" ></bean>
<context:annotation-config/>
<context:component-scan base-package="com.study.spring.sample.config" ></context:component-scan>
</beans>
然后我们的测试类代码
public class XMLConfigMain {
public static void main(String[] args) {
ApplicationContext context = new GenericXmlApplicationContext(
"classpath:com/study/spring/sample/config/application.xml");
BeanF bf = context.getBean(BeanF.class);
bf.do1();
}
}
处理的过程 解析XML --> BeanDefinition --> BeanDefinitionRegistry --> BeanFactory
2.基于注解方式
** ** 然后来看看基于注解方式的使用的情况。首先是我们的配置类
@Configuration
@ComponentScan("com.study.spring.sample.config")
public class JavaBasedMain {
@Bean
public BeanH getBeanH() {
return new BeanH();
}
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(JavaBasedMain.class);
BeanH bh = context.getBean(BeanH.class);
bh.doH();
}
}
然后是我们的测试类
public class AnnotationMain {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext("com.study.spring.sample.config");
BeanG bg = context.getBean(BeanG.class);
bg.dog();
}
}
注解使用有两种方法:
- 配置扫描路径
- 配置@Configuration的注解类
2.1 this构造方法
** ** 在this的构造方法中会完成相关的配置处理。
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
首先是AnnotatedBeanDefinitionReader(this)方法。会完成核心的ConfigurationClassPostProcessor的注入。ConfigurationClassPostProcessor 会完成@Configuration相关的注解的解析
this.scanner其实就是创建了一个对应的扫描器
2.2 扫描实现
** ** 扫描就需要进入到scan方法中。
完成相关的注册
2.3 @Configuration
** ** @Configuration的解析其实是在refresh方法中来实现的。
3.小结
** ** 通过上面的分析其实我们已经对Bean定义的扫描,解析和注册过程有了一定的了解。归纳为:
- reader解析XML,完成xml方法配置的bean定义
- scanner扫描指定包下的类,找出带有@Component注解的类,注册成Bean定义
- 通过ConfigurationClassPostProcessor对带有@Configuration注解的类进行处理,解析它上面的注解,以及类中带有@Bean 注解,加入这些的Bean的定义。
4.BeanDefinition
** ** ;然后我们来看看BeanDefinition的继承结构
** ** 继承属性访问器和元数据接口,增加了Bean定义操作,实现了数据和操作解耦。属性访问器和元数据接口接着往下看。
4.1 BeanMetadataElement
** ** BeanMetadataElement提供了获取数据源的方式,也就是可以指导Bean是来自哪个类。
public interface BeanMetadataElement {
/**
* Return the configuration source {@code Object} for this metadata element
* (may be {@code null}).
*/
@Nullable
default Object getSource() {
return null;
}
}
4.2 BeanMetadataAttribute元数据属性
** ** 实现了元数据接口,增加了属性的名字和值。。
public class BeanMetadataAttribute implements BeanMetadataElement {
private final String name;
@Nullable
private final Object value;
@Nullable
private Object source;
}
4.3 AttributeAccessor属性访问器
** ** AttributeAccessor用来给Bean定义了增删改查属性的功能
public interface AttributeAccessor {
/**
* Set the attribute defined by {@code name} to the supplied {@code value}.
* If {@code value} is {@code null}, the attribute is {@link #removeAttribute removed}.
* <p>In general, users should take care to prevent overlaps with other
* metadata attributes by using fully-qualified names, perhaps using
* class or package names as prefix.
* @param name the unique attribute key
* @param value the attribute value to be attached
*/
void setAttribute(String name, @Nullable Object value);
/**
* Get the value of the attribute identified by {@code name}.
* Return {@code null} if the attribute doesn't exist.
* @param name the unique attribute key
* @return the current value of the attribute, if any
*/
@Nullable
Object getAttribute(String name);
/**
* Remove the attribute identified by {@code name} and return its value.
* Return {@code null} if no attribute under {@code name} is found.
* @param name the unique attribute key
* @return the last value of the attribute, if any
*/
@Nullable
Object removeAttribute(String name);
/**
* Return {@code true} if the attribute identified by {@code name} exists.
* Otherwise return {@code false}.
* @param name the unique attribute key
*/
boolean hasAttribute(String name);
/**
* Return the names of all attributes.
*/
String[] attributeNames();
}
4.4 AttributeAccessorSupport属性访问抽象实现类
** ** 内部定义了1个map来存放属性。
public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
/** Map with String keys and Object values. */
private final Map<String, Object> attributes = new LinkedHashMap<>();
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Name must not be null");
if (value != null) {
this.attributes.put(name, value);
}
else {
removeAttribute(name);
}
}
// ......
}
4.5 BeanMetadataAttributeAccessor元数据属性访问器
** ** **继承AttributeAccessorSupport具备属性访问功能,实现BeanMetadataElement具备获取元数据功能。 ****AbstractBeanDefinition就继承于它,使得同时具有属性访问和元数据访问的功能 **。
结合AbstractBeanDefinition.来看看他们的类图结构
5. BeanDefinition继承体系
5.1 AnnotatedBeanDefinition
** ** 增加了2个方法,获取bean所在类的注解元数据和工厂方法元数据,这些数据在进行解析处理的时候需要用到。
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
* @return the annotation metadata object (never {@code null})
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
* @return the factory method metadata, or {@code null} if none
* @since 4.1.1
*/
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
** ** 该注解有三个具体的实现。ScannedGenericBeanDefinition、AnnotatedGenericBeanDefinition、ConfigurationClassBeanDefinition。
5.2 AbstractBeanDefinition模板类
** ** AbstractBeanDefinition我们可以称之为BeanDefinition的模板类。结构我们上面其实有梳理
** ** 通过上面我们可以看到AbstractBeanDefinition 具备了 Bean元数据的获取和属性相关的操作。同时AbstractBeanDefinition的继承结构
5.3 RootBeanDefinition根bean定义
** ** 它主要用在spring内部的bean定义、把不同类型的bean定义合并成RootBeanDefinition(getMergedLocalBeanDefinition方法)。没有实现BeanDefinition接口的设置获取父bean定义方法,不支持设置父子beanDefinition。
5.4 ConfigurationClassBeanDefinition
** ** 用作ConfigurationClassPostProcessor解析过程中封装配置类的bean定义。
5.5 GenericBeanDefinition
** ** GenericBeanDefinition通用Bean的定义。
5.6 ScannedGenericBeanDefinition
** ** @ComponentScan扫描的bean定义使用。
5.7 AnnotatedGenericBeanDefinition
Spring初始化源码分析
** ** 接下来我们详细分析下refresh方法的作用。
一、refresh方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1.context 为刷新做准备
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 2.让子类实现刷新内部持有BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 3.对beanFactory做一些准备工作:注册一些context回调、bean等
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 4.调用留给子类来提供实现逻辑的 对BeanFactory进行处理的钩子方法
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 5.执行context中注册的 BeanFactoryPostProcessor bean
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 6.注册BeanPostProcessor: 获得用户注册的BeanPostProcessor实例,注册到BeanFactory上
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 7.初始化国际化资源
initMessageSource();
// Initialize event multicaster for this context.
// 8.初始化Application event 广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 9.执行 有子类来提供实现逻辑的钩子方法 onRefresh
onRefresh();
// Check for listener beans and register them.
// 10.注册ApplicationListener: 获得用户注册的ApplicationListener Bean实例,注册到广播器上
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 11、完成剩余的单例Bean的实例化
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 12 发布对应的事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
二、prepareRefresh
** ** 完成一些刷新前的准备工作.
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
// 设置相关的状态
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
三、obtainFreshBeanFactory
** ** 在obtainFreshBeanFactory方法会完成BeanFactory对象的创建。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新容器
refreshBeanFactory();
return getBeanFactory();
}
如果是基于XML的方式使用会在refreshBeanFactory中完成配置文件的加载解析操作
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
// 销毁前面的 BeanFactory
destroyBeans();
closeBeanFactory();
}
try {
// 创建 BeanFactory 对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory); // 加载解析配置文件
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
四、prepareBeanFactory
** ** 上面的obtainFreshBeanFactory中完成了BeanFactory的创建和相关BeanDefinition对象的组装,然后在接下来的prepareBeanFactory中会完成相关的准备工作。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
// 设置beanFactory的classloader为当前context的classloader
beanFactory.setBeanClassLoader(getClassLoader());
// 设置beanfactory的表达式语言处理器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// 为beanFactory增加一个默认的propertyEditor,这个主要是对bean的属性等设置管理的一个工具类
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
// 添加beanPostProcessor,ApplicationContextAwareProcessor此类用来完成某些Aware对象的注入
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 设置要忽略自动装配的接口,很多同学理解不了为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set方法进行注入的,
// 所以在使用autowire进行注入的时候需要将这些接口进行忽略
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
// 设置几个自动装配的特殊规则,当在进行ioc初始化的如果有多个实现,那么就使用指定的对象进行注入
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
// 注册BPP
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
// 增加对AspectJ的支持,在java中织入分为三种方式,分为编译器织入,类加载器织入,运行期织入,编译器织入是指在java编译器,采用特殊的编译器,将切面织入到java类中,
// 而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面,运行期织入则是采用cglib和jdk进行切面的织入
// aspectj提供了两种织入方式,第一种是通过特殊编译器,在编译器,将aspectj语言编写的切面类织入到java类中,第二种是类加载期织入,就是下面的load time weaving,此处后续讲
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
// 注册默认的系统环境bean到一级缓存中
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
五、postProcessBeanFactory
** ** 该方法是一个空方法,交给子类自己处理的方法
六、invokeBeanFactoryPostProcessors
** ** invokeBeanFactoryPostProcessors是BeanFactory的后置处理方法。核心是会完成注册的BeanFactoryPostProcessor接口和BeanDefinitionRegistryPostProcessor的相关逻辑。invokeBeanFactoryPostProcessors是其核心的方法。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
// 无论是什么情况,优先执行BeanDefinitionRegistryPostProcessors
// 将已经执行过的BFPP存储在processedBeans中,防止重复执行
Set<String> processedBeans = new HashSet<>();
// 判断beanfactory是否是BeanDefinitionRegistry类型,此处是DefaultListableBeanFactory,实现了BeanDefinitionRegistry接口,所以为true
if (beanFactory instanceof BeanDefinitionRegistry) {
// 类型转换
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 此处希望大家做一个区分,两个接口是不同的,BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子集
// BeanFactoryPostProcessor主要针对的操作对象是BeanFactory,而BeanDefinitionRegistryPostProcessor主要针对的操作对象是BeanDefinition
// 存放BeanFactoryPostProcessor的集合
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 存放BeanDefinitionRegistryPostProcessor的集合
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 首先处理入参中的beanFactoryPostProcessors,遍历所有的beanFactoryPostProcessors,将BeanDefinitionRegistryPostProcessor
// 和BeanFactoryPostProcessor区分开
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// 如果是BeanDefinitionRegistryPostProcessor
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 直接执行BeanDefinitionRegistryPostProcessor接口中的postProcessBeanDefinitionRegistry方法
registryProcessor.postProcessBeanDefinitionRegistry(registry);
// 添加到registryProcessors,用于后续执行postProcessBeanFactory方法
registryProcessors.add(registryProcessor);
} else {
// 否则,只是普通的BeanFactoryPostProcessor,添加到regularPostProcessors,用于后续执行postProcessBeanFactory方法
regularPostProcessors.add(postProcessor);
}
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
// 用于保存本次要执行的BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// 调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类
// 找到所有实现BeanDefinitionRegistryPostProcessor接口bean的beanName
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 遍历处理所有符合规则的postProcessorNames
for (String ppName : postProcessorNames) {
// 检测是否实现了PriorityOrdered接口
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 获取名字对应的bean实例,添加到currentRegistryProcessors中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 将要被执行的BFPP名称添加到processedBeans,避免后续重复执行
processedBeans.add(ppName);
}
}
// 按照优先级进行排序操作
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 添加到registryProcessors中,用于最后执行postProcessBeanFactory方法
registryProcessors.addAll(currentRegistryProcessors);
// 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 执行完毕之后,清空currentRegistryProcessors
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
// 调用所有实现Ordered接口的BeanDefinitionRegistryPostProcessor实现类
// 找到所有实现BeanDefinitionRegistryPostProcessor接口bean的beanName,
// 此处需要重复查找的原因在于上面的执行过程中可能会新增其他的BeanDefinitionRegistryPostProcessor
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// 检测是否实现了Ordered接口,并且还未执行过
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
// 获取名字对应的bean实例,添加到currentRegistryProcessors中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 将要被执行的BFPP名称添加到processedBeans,避免后续重复执行
processedBeans.add(ppName);
}
}
// 按照优先级进行排序操作
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 添加到registryProcessors中,用于最后执行postProcessBeanFactory方法
registryProcessors.addAll(currentRegistryProcessors);
// 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 执行完毕之后,清空currentRegistryProcessors
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
// 最后,调用所有剩下的BeanDefinitionRegistryPostProcessors
boolean reiterate = true;
while (reiterate) {
reiterate = false;
// 找出所有实现BeanDefinitionRegistryPostProcessor接口的类
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 遍历执行
for (String ppName : postProcessorNames) {
// 跳过已经执行过的BeanDefinitionRegistryPostProcessor
if (!processedBeans.contains(ppName)) {
// 获取名字对应的bean实例,添加到currentRegistryProcessors中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 将要被执行的BFPP名称添加到processedBeans,避免后续重复执行
processedBeans.add(ppName);
reiterate = true;
}
}
// 按照优先级进行排序操作
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 添加到registryProcessors中,用于最后执行postProcessBeanFactory方法
registryProcessors.addAll(currentRegistryProcessors);
// 遍历currentRegistryProcessors,执行postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// 执行完毕之后,清空currentRegistryProcessors
currentRegistryProcessors.clear();
}
// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
// 调用所有BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 最后,调用入参beanFactoryPostProcessors中的普通BeanFactoryPostProcessor的postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
// Invoke factory processors registered with the context instance.
// 如果beanFactory不归属于BeanDefinitionRegistry类型,那么直接执行postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 到这里为止,入参beanFactoryPostProcessors和容器中的所有BeanDefinitionRegistryPostProcessor已经全部处理完毕,下面开始处理容器中
// 所有的BeanFactoryPostProcessor
// 可能会包含一些实现类,只实现了BeanFactoryPostProcessor,并没有实现BeanDefinitionRegistryPostProcessor接口
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// 找到所有实现BeanFactoryPostProcessor接口的类
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 用于存放实现了PriorityOrdered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 用于存放实现了Ordered接口的BeanFactoryPostProcessor的beanName
// List<String> orderedPostProcessorNames = new ArrayList<>();
List<BeanFactoryPostProcessor> orderedPostProcessor = new ArrayList<>();
// 用于存放普通BeanFactoryPostProcessor的beanName
// List<String> nonOrderedPostProcessorNames = new ArrayList<>();
List<BeanFactoryPostProcessor> nonOrderedPostProcessorNames = new ArrayList<>();
// 遍历postProcessorNames,将BeanFactoryPostProcessor按实现PriorityOrdered、实现Ordered接口、普通三种区分开
for (String ppName : postProcessorNames) {
// 跳过已经执行过的BeanFactoryPostProcessor
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
// 添加实现了PriorityOrdered接口的BeanFactoryPostProcessor到priorityOrderedPostProcessors
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
// 添加实现了Ordered接口的BeanFactoryPostProcessor的beanName到orderedPostProcessorNames
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
// orderedPostProcessorNames.add(ppName);
orderedPostProcessor.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else {
// 添加剩下的普通BeanFactoryPostProcessor的beanName到nonOrderedPostProcessorNames
// nonOrderedPostProcessorNames.add(ppName);
nonOrderedPostProcessorNames.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
}
// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
// 对实现了PriorityOrdered接口的BeanFactoryPostProcessor进行排序
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 遍历实现了PriorityOrdered接口的BeanFactoryPostProcessor,执行postProcessBeanFactory方法
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
// 创建存放实现了Ordered接口的BeanFactoryPostProcessor集合
// List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
// 遍历存放实现了Ordered接口的BeanFactoryPostProcessor名字的集合
// for (String postProcessorName : orderedPostProcessorNames) {
// 将实现了Ordered接口的BeanFactoryPostProcessor添加到集合中
// orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
// }
// 对实现了Ordered接口的BeanFactoryPostProcessor进行排序操作
// sortPostProcessors(orderedPostProcessors, beanFactory);
sortPostProcessors(orderedPostProcessor, beanFactory);
// 遍历实现了Ordered接口的BeanFactoryPostProcessor,执行postProcessBeanFactory方法
// invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessor, beanFactory);
// Finally, invoke all other BeanFactoryPostProcessors.
// 最后,创建存放普通的BeanFactoryPostProcessor的集合
// List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
// 遍历存放实现了普通BeanFactoryPostProcessor名字的集合
// for (String postProcessorName : nonOrderedPostProcessorNames) {
// 将普通的BeanFactoryPostProcessor添加到集合中
// nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
// }
// 遍历普通的BeanFactoryPostProcessor,执行postProcessBeanFactory方法
// invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(nonOrderedPostProcessorNames, beanFactory);
// Clear cached merged bean definitions since the post-processors might have
// modified the original metadata, e.g. replacing placeholders in values...
// 清除元数据缓存(mergeBeanDefinitions、allBeanNamesByType、singletonBeanNameByType)
// 因为后置处理器可能已经修改了原始元数据,例如,替换值中的占位符
beanFactory.clearMetadataCache();
}
要搞清楚上面的代码含义首先需要搞清楚出这两者之间的关系
实现的核心流程是
**在这个位置核心的代表是 **ConfigurationClassPostProcessor
用来处理 @Configuration
注解表示的Java类,来处理其中的@Bean,@Primary等注解。
七、registerBeanPostProcessors
** ** 完成Bean对象的相关后置处理器的注册。具体的代码逻辑和上面是差不多的。
/**
* 注册beanPostProcessor
* @param beanFactory
* @param applicationContext
*/
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 找到所有实现了BeanPostProcessor接口的类
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// Register BeanPostProcessorChecker that logs an info message when
// a bean is created during BeanPostProcessor instantiation, i.e. when
// a bean is not eligible for getting processed by all BeanPostProcessors.
// 记录下BeanPostProcessor的目标计数
// 此处为什么要+1呢,原因非常简单,在此方法的最后会添加一个BeanPostProcessorChecker的类
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// 添加BeanPostProcessorChecker(主要用于记录信息)到beanFactory中
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// Separate between BeanPostProcessors that implement PriorityOrdered,
// Ordered, and the rest.
// 定义存放实现了PriorityOrdered接口的BeanPostProcessor集合
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// 定义存放spring内部的BeanPostProcessor
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
// 定义存放实现了Ordered接口的BeanPostProcessor的name集合
List<String> orderedPostProcessorNames = new ArrayList<>();
// 定义存放普通的BeanPostProcessor的name集合
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// 遍历beanFactory中存在的BeanPostProcessor的集合postProcessorNames,
for (String ppName : postProcessorNames) {
// 如果ppName对应的BeanPostProcessor实例实现了PriorityOrdered接口,则获取到ppName对应的BeanPostProcessor的实例添加到priorityOrderedPostProcessors中
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
// 如果ppName对应的BeanPostProcessor实例也实现了MergedBeanDefinitionPostProcessor接口,那么则将ppName对应的bean实例添加到internalPostProcessors中
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 如果ppName对应的BeanPostProcessor实例没有实现PriorityOrdered接口,但是实现了Ordered接口,那么将ppName对应的bean实例添加到orderedPostProcessorNames中
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
} else {
// 否则将ppName添加到nonOrderedPostProcessorNames中
nonOrderedPostProcessorNames.add(ppName);
}
}
// First, register the BeanPostProcessors that implement PriorityOrdered.
// 首先,对实现了PriorityOrdered接口的BeanPostProcessor实例进行排序操作
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 注册实现了PriorityOrdered接口的BeanPostProcessor实例添加到beanFactory中
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
// 注册所有实现Ordered的beanPostProcessor
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
// 根据ppName找到对应的BeanPostProcessor实例对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// 将实现了Ordered接口的BeanPostProcessor添加到orderedPostProcessors集合中
orderedPostProcessors.add(pp);
// 如果ppName对应的BeanPostProcessor实例也实现了MergedBeanDefinitionPostProcessor接口,那么则将ppName对应的bean实例添加到internalPostProcessors中
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 对实现了Ordered接口的BeanPostProcessor进行排序操作
sortPostProcessors(orderedPostProcessors, beanFactory);
// 注册实现了Ordered接口的BeanPostProcessor实例添加到beanFactory中
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors.
// 创建存放没有实现PriorityOrdered和Ordered接口的BeanPostProcessor的集合
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
// 遍历集合
for (String ppName : nonOrderedPostProcessorNames) {
// 根据ppName找到对应的BeanPostProcessor实例对象
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// 将没有实现PriorityOrdered和Ordered接口的BeanPostProcessor添加到nonOrderedPostProcessors集合中
nonOrderedPostProcessors.add(pp);
// 如果ppName对应的BeanPostProcessor实例也实现了MergedBeanDefinitionPostProcessor接口,那么则将ppName对应的bean实例添加到internalPostProcessors中
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
// 注册没有实现PriorityOrdered和Ordered的BeanPostProcessor实例添加到beanFactory中
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors.
// 将所有实现了MergedBeanDefinitionPostProcessor类型的BeanPostProcessor进行排序操作
sortPostProcessors(internalPostProcessors, beanFactory);
// 注册所有实现了MergedBeanDefinitionPostProcessor类型的BeanPostProcessor到beanFactory中
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register post-processor for detecting inner beans as ApplicationListeners,
// moving it to the end of the processor chain (for picking up proxies etc).
// 注册ApplicationListenerDetector到beanFactory中
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
八、initMessageSource
** ** 为上下文初始化message源,即不同语言的消息体,国际化处理.此处不过多介绍、
九、initApplicationEventMulticaster
** ** initApplicationEventMulticaster初始化事件监听多路广播器.
protected void initApplicationEventMulticaster() {
// 获取当前bean工厂,一般是DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断容器中是否存在bdName为applicationEventMulticaster的bd,也就是说自定义的事件监听多路广播器,必须实现ApplicationEventMulticaster接口
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 如果有,则从bean工厂得到这个bean对象
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 如果没有,则默认采用SimpleApplicationEventMulticaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
代码很简单,创建了一个SimpleApplicationEventMulticaster对象,来广播相关的消息事件。
十、onRefresh
** ** 留给子类来初始化其他的bean
十一、registerListeners
** ** 所有注册的bean中查找listener bean,注册到消息广播器中.
protected void registerListeners() {
// Register statically specified listeners first.
// 遍历应用程序中存在的监听器集合,并将对应的监听器添加到监听器的多路广播器中
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
// 从容器中获取所有实现了ApplicationListener接口的bd的bdName
// 放入ApplicationListenerBeans集合中
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
// getApplicationEventMulticaster().addApplicationListener(this.getBean(listenerBeanName,ApplicationListener.class));
}
// Publish early application events now that we finally have a multicaster...
// 此处先发布早期的监听器集合
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
十二、finishBeanFactoryInitialization
** ** finishBeanFactoryInitialization初始化剩下的单实例(非懒加载的).这个专门单独讲解
十三、finishRefresh
** ** finishRefresh完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人.
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清除上下文级别的资源缓存(如扫描的ASM元数据)
// 清空在资源加载器中的所有资源缓存
clearResourceCaches();
// Initialize lifecycle processor for this context.
// 为这个上下文初始化生命周期处理器
// 初始化LifecycleProcessor.如果上下文中找到'lifecycleProcessor'的LifecycleProcessor Bean对象,
// 则使用DefaultLifecycleProcessor
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
// 首先将刷新传播到生命周期处理器
// 上下文刷新的通知,例如自动启动的组件
getLifecycleProcessor().onRefresh();
// Publish the final event.
// 发布最终事件
// 新建ContextRefreshedEvent事件对象,将其发布到所有监听器。
publishEvent(new ContextRefreshedEvent(this));
// Participate in LiveBeansView MBean, if active.
// 参与LiveBeansView MBean,如果是活动的
// LiveBeansView:Sping用于支持JMX 服务的类
// 注册当前上下文到LiveBeansView,以支持JMX服务
LiveBeansView.registerApplicationContext(this);
}
Spring源码-Bean的实例化
** ** 接下来我们看看Bean的实例化处理
一、BeanDefinition
** ** **首先我们来看看BeanDefinition的存放位置。因为Bean对象的实例化肯定是BeanFactory基于对应的BeanDefinition的定义来实现的,所以在这个过程中BeanDefinition是非常重要的,前面的课程讲解已经完成了BeanDefinition的定义。同时根据前面refresh方法的讲解我们知道了BeanFactory的具体实现是 **DefaultListableBeanFactory
.所以BeanDefinition的相关信息是存储在 DefaultListableBeanFactory
的相关属性中的。
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new
ConcurrentHashMap<>(256);
二、Bean实例的创建过程
** ** 然后就是Bean实例的创建过程。这块儿我们可以通过Debug的形式非常直观的看到。
** ** 按照这种步骤一个个去分析就OK了。
三、单例对象
** ** 在创建单例对象的时候是如何保存单例的特性的?这块我们需要注意下面的代码
然后进入到getSingleton方法中。
创建成功的单例对象会被缓存起来。在 addSingleton 方法中
所以singletonObjects是缓存所有Bean实例的容器
而具体创建单例Bean的逻辑会回调前面的Lambda表达式中的createBean方法
四、单例对象的销毁
** ** 然后我们先来看下一个单例Bean对象的销毁过程。定义一个案例
**然后我们在测试的案例中显示的调用 **close
方法
执行的时候可以看到相关的日志执行了。
进入到close方法中分析,比较核心的有两个位置。在doClose方法中。
具体销毁的代码进入destroyBeans()中查看即可。
在doClose方法中有个提示。registerShutdownHook方法
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
对应的在web项目中就有对应的调用
这个就是Bean实例化的过程了,当然在实例化中的DI问题我们在下篇文章中重点分析。
Spring源码-DI的过程
** ** 接下来我们分析下Spring源码中Bean初始化过程中的DI过程。也就是属性的依赖注入。
一、构造参数依赖
1. 如何确定构造方法
** ** 在Spring中生成Bean实例的时候默认是调用对应的无参构造方法来处理。
@Component
public class BeanK {
private BeanE beanE;
private BeanF beanF;
public BeanK(BeanE beanE) {
this.beanE = beanE;
}
public BeanK(BeanE beanE, BeanF beanF) {
this.beanE = beanE;
this.beanF = beanF;
}
}
声明了两个构造方法,但是没有提供无参的构造方法。这时从容器中获取会报错。
这时我们需要在显示使用的构造方法中添加@Autowired注解即可
源码层面的核心
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 确认需要创建的bean实例的类可以实例化
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 确保class不为空,并且访问权限是public
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 判断当前beanDefinition中是否包含实例供应器,此处相当于一个回调方法,利用回调方法来创建bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 如果工厂方法不为空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
// Shortcut when re-creating the same bean...
// 标记下,防止重复创建同一个bean
boolean resolved = false;
// 是否需要自动装配
boolean autowireNecessary = false;
// 如果没有参数
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 因为一个类可能由多个构造函数,所以需要根据配置文件中配置的参数或传入的参数来确定最终调用的构造函数。
// 因为判断过程会比较,所以spring会将解析、确定好的构造函数缓存到BeanDefinition中的resolvedConstructorOrFactoryMethod字段中。
// 在下次创建相同时直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值获取,避免再次解析
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 有构造参数的或者工厂方法
if (resolved) {
// 构造器有参数
if (autowireNecessary) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
// 从bean后置处理器中为自动装配寻找构造方法, 有且仅有一个有参构造或者有且仅有@Autowired注解构造
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 以下情况符合其一即可进入
// 1、存在可选构造方法
// 2、自动装配模型为构造函数自动装配
// 3、给BeanDefinition中设置了构造参数值
// 4、有参与构造函数参数列表的参数
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 找出最合适的默认构造方法
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 使用默认无参构造函数创建对象,如果没有无参构造且存在多个有参构造且没有@AutoWired注解构造,会报错
return instantiateBean(beanName, mbd);
}
2. 循环依赖
** ** 接下来我们看看在构造注入的情况下。对循环依赖的检测是怎么做的。前面我们分析过,在构造注入的情况下,对于循环依赖是没有办法解决的。只能检测,然后抛出对应的异常信息。
@Component
public class BeanL {
private BeanM beanM;
@Autowired
public BeanL(BeanM beanM) {
this.beanM = beanM;
}
}
@Component
public class BeanM {
private BeanL beanL;
@Autowired
public BeanM(BeanL beanL) {
this.beanL = beanL;
}
}
然后启动代码看到循环依赖的报错
然后我们来看看他是如何实现循环检测的。
**进入到这个 **beforeSingletonCreation
方法中。
protected void beforeSingletonCreation(String beanName) {
// 如果当前在创建检查中的排除bean名列表中不包含该beanName且将beanName添加到当前正在创建的bean名称列表后,出现
// beanName已经在当前正在创建的bean名称列表中添加过
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
// 抛出当前正在创建的Bean异常
throw new BeanCurrentlyInCreationException(beanName);
}
}
然后当对象创建完成后。会异常对应的检测
protected void afterSingletonCreation(String beanName) {
// 如果当前在创建检查中的排除bean名列表中不包含该beanName且将beanName从当前正在创建的bean名称列表异常后,出现
// beanName已经没在当前正在创建的bean名称列表中出现过
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
// 抛出非法状态异常:单例'beanName'不是当前正在创建的
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
当然上面的针对单例的处理,如果是原型的话。我们继续来看
// 原型模式的bean对象创建
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
// 它是一个原型 -> 创建一个新实例
// 定义prototype实例
Object prototypeInstance = null;
try {
// 创建Prototype对象前的准备工作,默认实现将beanName添加到prototypesCurrentlyInCreation中
beforePrototypeCreation(beanName);
// 为mbd(和参数)创建一个bean实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 创建完prototype实例后的回调,默认是将beanName从prototypesCurrentlyInCreation移除
afterPrototypeCreation(beanName);
}
// 从beanInstance中获取公开的Bean对象,主要处理beanInstance是FactoryBean对象的情况,如果不是
// FactoryBean会直接返回beanInstance实例
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
而且我们可以发现在原型对象的检测中使用的是ThreadLocal来存储了
二、属性依赖
** ** **然后我们来看看Bean的属性依赖的处理。属性依赖的具体方法是 **polulateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果beanWrapper为空
if (bw == null) {
// 如果mbd有需要设置的属性
if (mbd.hasPropertyValues()) {
// 抛出bean创建异常
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
// 没有可填充的属性,直接跳过
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// 给任何实现了InstantiationAwareBeanPostProcessors的子类机会去修改bean的状态再设置属性之前,可以被用来支持类型的字段注入
// 否是"synthetic"。一般是指只有AOP相关的pointCut配置或者Advice配置才会将 synthetic设置为true
// 如果mdb是不是'syntheic'且工厂拥有InstantiationAwareBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//遍历工厂中的BeanPostProcessor对象
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果 bp 是 InstantiationAwareBeanPostProcessor 实例
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// //postProcessAfterInstantiation:一般用于设置属性
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
//PropertyValues:包含以一个或多个PropertyValue对象的容器,通常包括针对特定目标Bean的一次更新
//如果mdb有PropertyValues就获取其PropertyValues
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 获取 mbd 的 自动装配模式
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 如果 自动装配模式 为 按名称自动装配bean属性 或者 按类型自动装配bean属性
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//MutablePropertyValues:PropertyValues接口的默认实现。允许对属性进行简单操作,并提供构造函数来支持从映射 进行深度复制和构造
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// 根据autotowire的名称(如适用)添加属性值
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
//通过bw的PropertyDescriptor属性名,查找出对应的Bean对象,将其添加到newPvs中
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// 根据自动装配的类型(如果适用)添加属性值
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//通过bw的PropertyDescriptor属性类型,查找出对应的Bean对象,将其添加到newPvs中
autowireByType(beanName, mbd, bw, newPvs);
}
//让pvs重新引用newPvs,newPvs此时已经包含了pvs的属性值以及通过AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE自动装配所得到的属性值
pvs = newPvs;
}
//工厂是否拥有InstiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//mbd.getDependencyCheck(),默认返回 DEPENDENCY_CHECK_NONE,表示 不检查
//是否需要依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
//经过筛选的PropertyDesciptor数组,存放着排除忽略的依赖项或忽略项上的定义的属性
PropertyDescriptor[] filteredPds = null;
//如果工厂拥有InstiationAwareBeanPostProcessor,那么处理对应的流程,主要是对几个注解的赋值工作包含的两个关键子类是CommonAnnoationBeanPostProcessor,AutowiredAnnotationBeanPostProcessor
if (hasInstAwareBpps) {
//如果pvs为null
if (pvs == null) {
//尝试获取mbd的PropertyValues
pvs = mbd.getPropertyValues();
}
//遍历工厂内的所有后置处理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//如果 bp 是 InstantiationAwareBeanPostProcessor 的实例
if (bp instanceof InstantiationAwareBeanPostProcessor) {
//将bp 强转成 InstantiationAwareBeanPostProcessor 对象
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//postProcessProperties:在工厂将给定的属性值应用到给定Bean之前,对它们进行后处理,不需要任何属性扫描符。该回调方法在未来的版本会被删掉。
// -- 取而代之的是 postProcessPropertyValues 回调方法。
// 让ibp对pvs增加对bw的Bean对象的propertyValue,或编辑pvs的proertyValue
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
//如果pvs为null
if (pvsToUse == null) {
//如果filteredPds为null
if (filteredPds == null) {
//mbd.allowCaching:是否允许缓存,默认时允许的。缓存除了可以提高效率以外,还可以保证在并发的情况下,返回的PropertyDesciptor[]永远都是同一份
//从bw提取一组经过筛选的PropertyDesciptor,排除忽略的依赖项或忽略项上的定义的属性
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//postProcessPropertyValues:一般进行检查是否所有依赖项都满足,例如基于"Require"注释在 bean属性 setter,
// -- 替换要应用的属性值,通常是通过基于原始的PropertyValues创建一个新的MutablePropertyValue实例, 添加或删除特定的值
// -- 返回的PropertyValues 将应用于bw包装的bean实例 的实际属性值(添加PropertyValues实例到pvs 或者 设置为null以跳过属性填充)
//回到ipd的postProcessPropertyValues方法
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
//如果pvsToUse为null,将终止该方法精致,以跳过属性填充
if (pvsToUse == null) {
return;
}
}
//让pvs引用pvsToUse
pvs = pvsToUse;
}
}
}
//如果需要依赖检查
if (needsDepCheck) {
//如果filteredPds为null
if (filteredPds == null) {
//从bw提取一组经过筛选的PropertyDesciptor,排除忽略的依赖项或忽略项上的定义的属性
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
//检查依赖项:主要检查pd的setter方法需要赋值时,pvs中有没有满足其pd的需求的属性值可供其赋值
checkDependencies(beanName, mbd, filteredPds, pvs);
}
//如果pvs不为null
if (pvs != null) {
//应用给定的属性值,解决任何在这个bean工厂运行时其他bean的引用。必须使用深拷贝,所以我们 不会永久地修改这个属性
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
1. 提前暴露
** ** 然后来看看是如何处理循环依赖的。
**对应的 **addSingletonFactory
方法
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
// 使用singletonObjects进行加锁,保证线程安全
synchronized (this.singletonObjects) {
// 如果单例对象的高速缓存【beam名称-bean实例】没有beanName的对象
if (!this.singletonObjects.containsKey(beanName)) {
// 将beanName,singletonFactory放到单例工厂的缓存【bean名称 - ObjectFactory】
this.singletonFactories.put(beanName, singletonFactory);
// 从早期单例对象的高速缓存【bean名称-bean实例】 移除beanName的相关缓存对象
this.earlySingletonObjects.remove(beanName);
// 将beanName添加已注册的单例集中
this.registeredSingletons.add(beanName);
}
}
}
2. 循环依赖
循环依赖的图解
相关代码介绍
getEarlyBeanReference方法
getSingleton方法
Spring源码-AOP分析
一、手写AOP回顾
** ** 本文我们开始讲解Spring中的AOP原理和源码,我们前面手写了AOP的实现,了解和自己实现AOP应该要具备的内容,我们先回顾下,这对我们理解Spring的AOP是非常有帮助的。
1. 涉及的相关概念
** ** 先回顾下核心的概念,比如:Advice,Pointcut,Aspect等
更加形象的描述:
2. 相关核心的设计
Advice:
Pointcut:
Aspect:
Advisor:
织入:
二、AOP相关概念的类结构
** ** 回顾了前面的内容,然后我们来看看Spring中AOP是如何来实现的了。
1. Advice类结构
** ** 我们先来看看Advice的类结构,advice--》通知,需要增强的功能
相关的说明
2. Pointcut类结构
** ** 然后来看看Pointcut的设计,也就是切入点的处理。
Pointcut的两种实现方式
3. Advisor类结构
** ** Advisor的类结构比较简单。一个是PointcutAdvisor,一个是IntroductionAdvisor
我们要看的重点是 PointcutAdvisor 及实现 AspectJPointcutAdvisor。
三、织入的实现
1. BeanPostProcessor
1.1 案例演示
** ** 我们通过案例来看,首先使用AOP来增强。
定义切面类
/**
* 切面类
*/
@Component
@EnableAspectJAutoProxy
@Aspect
public class AspectAdviceBeanUseAnnotation {
// 定义一个全局的Pointcut
@Pointcut("execution(* com.study.spring.sample.aop.*.do*(..))")
public void doMethods() {
}
@Pointcut("execution(* com.study.spring.sample.aop.*.service*(..))")
public void services() {
}
// 定义一个Before Advice
@Before("doMethods() and args(tk,..)")
public void before3(String tk) {
System.out.println("----------- AspectAdviceBeanUseAnnotation before3 增强 参数tk= " + tk);
}
@Around("services() and args(name,..)")
public Object around2(ProceedingJoinPoint pjp, String name) throws Throwable {
System.out.println("--------- AspectAdviceBeanUseAnnotation arround2 参数 name=" + name);
System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-前增强 for " + pjp);
Object ret = pjp.proceed();
System.out.println("----------- AspectAdviceBeanUseAnnotation arround2 环绕-后增强 for " + pjp);
return ret;
}
@AfterReturning(pointcut = "services()", returning = "retValue")
public void afterReturning(Object retValue) {
System.out.println("----------- AspectAdviceBeanUseAnnotation afterReturning 增强 , 返回值为: " + retValue);
}
@AfterThrowing(pointcut = "services()", throwing = "e")
public void afterThrowing(JoinPoint jp, Exception e) {
System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强 for " + jp);
System.out.println("----------- AspectAdviceBeanUseAnnotation afterThrowing 增强 异常 :" + e);
}
@After("doMethods()")
public void after(JoinPoint jp) {
System.out.println("----------- AspectAdviceBeanUseAnnotation after 增强 for " + jp);
}
/*
* BeanDefinitionRegistryPostProcessor BeanFactoryPostProcessor
* InstantiationAwareBeanPostProcessor Bean实例创建前后 BeanPostProcessor
*/
}
需要增强的目标类
@Component
public class BeanQ {
public void do1(String task, int time) {
System.out.println("-------------do1 do " + task + " time:" + time);
}
public String service1(String name) {
System.out.println("-------------servce1 do " + name);
return name;
}
public String service2(String name) {
System.out.println("-------------servce2 do " + name);
if (!"s1".equals(name)) {
throw new IllegalArgumentException("参数 name != s1, name=" + name);
}
return name + " hello!";
}
}
测试代码
@Configuration
@ComponentScan
public class AopMainAnno {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AopMainAnno.class);
BeanQ bq = context.getBean(BeanQ.class);
bq.do1("task1", 20);
System.out.println();
bq.service1("service1");
System.out.println();
bq.service2("s1");
}
}
执行即可看到增强的效果
1.2 @EnableAspectJAutoProxy
** ** 我们需要使用代理增强处理,必须添加@EnableAspectJAutoProxy才生效。我们来看看他做了什么事情
在registerOrEscalateApcAsRequired方法中会把上面的Java类注入到容器中。
所以我们需要看看 AnnotationAwareAspectJAutoProxyCreator 的结构
1.3 AnnotationAwareAspectJAutoProxyCreator
** ** 我们直接来看类图结构,可以发现其本质就是一个 BeanPostProcessor ,只是扩展了更多的功能。
那么具体处理的逻辑
1.4 如何串联
** ** Bean的IoC是如何和对应的BeanPostProcessor串联的呢?我们来看看。
isInfrastructureClass方法判断是否是基础设施
shouldSkip:是否应该跳过,会完成相关的advisor的收集
具体的处理流程
public List<Advisor> findAdvisorBeans() {
// Determine list of advisor bean names, if not cached already.
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the auto-proxy creator apply to them!
// 获取当前BeanFactory中所有实现了Advisor接口的bean的名称
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
// 对获取到的实现Advisor接口的bean的名称进行遍历
List<Advisor> advisors = new ArrayList<>();
// 循环所有的beanName,找出对应的增强方法
for (String name : advisorNames) {
// isEligibleBean()是提供的一个hook方法,用于子类对Advisor进行过滤,这里默认返回值都是true
if (isEligibleBean(name)) {
// 如果当前bean还在创建过程中,则略过,其创建完成之后会为其判断是否需要织入切面逻辑
if (this.beanFactory.isCurrentlyInCreation(name)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping currently created advisor '" + name + "'");
}
}
else {
try {
// 将当前bean添加到结果中
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
catch (BeanCreationException ex) {
// 对获取过程中产生的异常进行封装
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
String bceBeanName = bce.getBeanName();
if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
if (logger.isTraceEnabled()) {
logger.trace("Skipping advisor '" + name +
"' with dependency on currently created bean: " + ex.getMessage());
}
// Ignore: indicates a reference back to the bean we're trying to advise.
// We want to find advisors other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
}
}
return advisors;
}
2. 代理类的结构
** ** 在上面的分析中出现了很多代理相关的代码,为了更好的理解,我们来梳理下Spring中的代理相关的结构
2.1 AopProxy
** ** 在Spring中创建代理对象都是通过AopProxy这个接口的两个具体实现类来实现的,也就是jdk和cglib两种方式。
2.2 AopProxyFactory
** ** 在Spring中通过AopProxyFactory这个工厂类来提供AopProxy。
默认的实现类是DefaultAopProxyFactory
/**
* 真正的创建代理,判断一些列条件,有自定义的接口的就会创建jdk代理,否则就是cglib
* @param config the AOP configuration in the form of an
* AdvisedSupport object
* @return
* @throws AopConfigException
*/
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 这段代码用来判断选择哪种创建代理对象的方式
// config.isOptimize() 是否对代理类的生成使用策略优化 其作用是和isProxyTargetClass是一样的 默认为false
// config.isProxyTargetClass() 是否使用Cglib的方式创建代理对象 默认为false
// hasNoUserSuppliedProxyInterfaces目标类是否有接口存在 且只有一个接口的时候接口类型不是SpringProxy类型
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
// 上面的三个方法有一个为true的话,则进入到这里
// 从AdvisedSupport中获取目标类 类对象
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 判断目标类是否是接口 如果目标类是接口的话,则还是使用JDK的方式生成代理对象
// 如果目标类是Proxy类型 则还是使用JDK的方式生成代理对象
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 配置了使用Cglib进行动态代理或者目标类没有接口,那么使用Cglib的方式创建代理对象
return new ObjenesisCglibAopProxy(config);
}
else {
// 使用JDK的提供的代理方式生成代理对象
return new JdkDynamicAopProxy(config);
}
}
2.3 ProxyFactory
** ** ProxyFactory代理对象的工厂类,用来创建代理对象的工厂。
然后我们来看看 ProxyFactory的体系结构
ProxyConfig
这个类主要保存代理的信息,如果是否使用类代理,是否要暴露代理等。
public class ProxyConfig implements Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = -8409359707199703185L;
// 是否代理的对象是类,动态代理分为代理接口和类,这里的属性默认是代理的接口
private boolean proxyTargetClass = false;
// 是否进行主动优化,默认是不会主动优化
private boolean optimize = false;
// 是否由此配置创建的代理不能被转成Advised类型,默认时候可转
boolean opaque = false;
// 是否会暴露代理在调用的时候,默认是不会暴露
boolean exposeProxy = false;
// 是否冻结此配置,不能被修改
private boolean frozen = false;
}
Advised
由持有 AOP 代理工厂配置的类实现的接口。此配置包括拦截器和其他advice、advisor和代理接口。从 Spring 获得的任何 AOP 代理都可以转换为该接口,以允许操作其 AOP 通知。
AdvisedSupport
- AOP代理配置管理器的基类。 此类的子类通常是工厂,从中可以直接获取 AOP 代理实例。此类可释放Advices和Advisor的内部管理子类,但实际上并没有实现代理创建方法,实现由子类提供
- AdvisedSupport实现了Advised中处理Advisor和Advice的方法,添加Advice时会被包装成一个Advisor,默认使用的Advisor是DefaultPointcutAdvisor,DefaultPointcutAdvisor默认的Pointcut是TruePointcut(转换为一个匹配所有方法调用的Advisor与代理对象绑定)。
- AdvisedSupport同时会缓存对于某一个方法对应的所有Advisor(Map<MethodCacheKey, List<Object>> methodCache),当Advice或Advisor发生变化时,会清空该缓存。getInterceptorsAndDynamicInterceptionAdvice用来获取对应代理方法对应有效的拦截器链 。
ProxyCreatorSupport
** ** 继承了AdvisedSupport,ProxyCreatorSupport正是实现代理的创建方法,ProxyCreatorSupport有一个成员变量AopProxyFactory,而该变量的值默认是DefaultAopProxyFactory
这个也就和前面的AopProxyFactory串联起来了。
3. @Aspect解析
** ** 然后我们分析下@Aspect注解的解析过程
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// TODO: Consider optimization by caching the list of the aspect names
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
先进入到shouldSkip方法。然后进入到 findCandidateAdvisors方法。
/**
* 查找通知器
* @return
*/
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
// 找到系统中实现了Advisor接口的bean
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 找到系统中使用@Aspect标注的bean,并且找到该bean中使用@Before,@After等标注的方法,
// 将这些方法封装为一个个Advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
在这个方法中就可以看到@Aspect 注解的处理了,进入到buildAspectJAdvisors方法
public List<Advisor> buildAspectJAdvisors() {
// 获取切面名字列表
List<String> aspectNames = this.aspectBeanNames;
// 缓存字段aspectNames没有值,注意实例化第一个单实例bean的时候就会触发解析切面
if (aspectNames == null) {
// 双重检查
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// 用于保存所有解析出来的Advisors集合对象
List<Advisor> advisors = new ArrayList<>();
// 用于保存切面的名称的集合
aspectNames = new ArrayList<>();
/**
* AOP功能中在这里传入的是Object对象,代表去容器中获取到所有的组件的名称,然后再
* 进行遍历,这个过程是十分的消耗性能的,所以说Spring会再这里加入了保存切面信息的缓存。
* 但是事务功能不一样,事务模块的功能是直接去容器中获取Advisor类型的,选择范围小,且不消耗性能。
* 所以Spring在事务模块中没有加入缓存来保存我们的事务相关的advisor
*/
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
// 遍历我们从IOC容器中获取处的所有Bean的名称
for (String beanName : beanNames) {
// 判断当前bean是否为子类定制的需要过滤的bean
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
// 通过beanName去容器中获取到对应class对象
Class<?> beanType = this.beanFactory.getType(beanName, false);
if (beanType == null) {
continue;
}
// 判断当前bean是否使用了@Aspect注解进行标注
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
// 对于使用了@Aspect注解标注的bean,将其封装为一个AspectMetadata类型。
// 这里在封装的过程中会解析@Aspect注解上的参数指定的切面类型,如perthis
// 和pertarget等。这些被解析的注解都会被封装到其perClausePointcut属性中
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 判断@Aspect注解中标注的是否为singleton类型,默认的切面类都是singleton类型
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
// 将BeanFactory和当前bean封装为MetadataAwareAspect-
// InstanceFactory对象,这里会再次将@Aspect注解中的参数都封装
// 为一个AspectMetadata,并且保存在该factory中
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 通过封装的bean获取其Advice,如@Before,@After等等,并且将这些
// Advice都解析并且封装为一个个的Advisor
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 如果切面类是singleton类型,则将解析得到的Advisor进行缓存,
// 否则将当前的factory进行缓存,以便再次获取时可以通过factory直接获取
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
// 如果@Aspect注解标注的是perthis和pertarget类型,说明当前切面
// 不可能是单例的,因而这里判断其如果是单例的则抛出异常
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
// 将当前BeanFactory和切面bean封装为一个多例类型的Factory
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
// 对当前bean和factory进行缓存
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
// 通过所有的aspectNames在缓存中获取切面对应的Advisor,这里如果是单例的,则直接从advisorsCache
// 获取,如果是多例类型的,则通过MetadataAwareAspectInstanceFactory立即生成一个
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
// 如果是单例的Advisor bean,则直接添加到返回值列表中
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
// 如果是多例的Advisor bean,则通过MetadataAwareAspectInstanceFactory生成
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
然后我们需要看看 this.advisorFactory.getAdvisors(factory) 方法:完成 切入点表达式和对应Advice增强的方法绑定为Advisor。
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
// 获取标记为AspectJ的类
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
// 获取标记为AspectJ的name
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
// 对当前切面bean进行校验,主要是判断其切点是否为perflow或者是percflowbelow,Spring暂时不支持
// 这两种类型的切点
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
// 将当前aspectInstanceFactory进行封装,这里LazySingletonAspectInstanceFactoryDecorator
// 使用装饰器模式,主要是对获取到的切面实例进行了缓存,保证每次获取到的都是同一个切面实例
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
// 这里getAdvisorMethods()会获取所有的没有使用@Pointcut注解标注的方法,然后对其进行遍历
for (Method method : getAdvisorMethods(aspectClass)) {
// Prior to Spring Framework 5.2.7, advisors.size() was supplied as the declarationOrderInAspect
// to getAdvisor(...) to represent the "current position" in the declared methods list.
// However, since Java 7 the "current position" is not valid since the JDK no longer
// returns declared methods in the order in which they are declared in the source code.
// Thus, we now hard code the declarationOrderInAspect to 0 for all advice methods
// discovered via reflection in order to support reliable advice ordering across JVM launches.
// Specifically, a value of 0 aligns with the default value used in
// AspectJPrecedenceComparator.getAspectDeclarationOrder(Advisor).
// 判断当前方法是否标注有@Before,@After或@Around等注解,如果标注了,则将其封装为一个Advisor
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
// 这里的isLazilyInstantiated()方法判断的是当前bean是否应该被延迟初始化,其主要是判断当前
// 切面类是否为perthis,pertarget或pertypewithiin等声明的切面。因为这些类型所环绕的目标bean
// 都是多例的,因而需要在运行时动态判断目标bean是否需要环绕当前的切面逻辑
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
// 如果Advisor不为空,并且是需要延迟初始化的bean,则在第0位位置添加一个同步增强器,
// 该同步增强器实际上就是一个BeforeAspect的Advisor
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
// 判断属性上是否包含有@DeclareParents注解标注的需要新添加的属性,如果有,则将其封装为一个Advisor
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
然后我们需要关注的方法 根据对应的方法获取对应的Advisor 通知。
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
// 校验当前切面类是否使用了perflow或者percflowbelow标识的切点,Spring暂不支持这两种切点
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获取当前方法中@Before,@After或者@Around等标注的注解,并且获取该注解的值,将其
// 封装为一个AspectJExpressionPointcut对象
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 将获取到的切点,切点方法等信息封装为一个Advisor对象,也就是说当前Advisor包含有所有
// 当前切面进行环绕所需要的信息
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
4. 多个切面的责任链实现
代理方法
invoke方法的处理
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 获取到我们的目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 若是equals方法不需要代理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
// 若是hashCode方法不需要代理
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
// 若是DecoratingProxy也不要拦截器执行
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// isAssignableFrom方法:如果调用这个方法的class或接口与参数cls表示的类或接口相同,或者是参数cls表示的类或接口的父类,则返回true
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
/**
* 这个配置是暴露我们的代理对象到线程变量中,需要搭配@EnableAspectJAutoProxy(exposeProxy = true)一起使用
* 比如在目标对象方法中再次获取代理对象可以使用这个AopContext.currentProxy()
* 还有的就是事务方法调用事务方法的时候也是用到这个
*/
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
// 把我们的代理对象暴露到线程变量中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
// 获取我们的目标对象
target = targetSource.getTarget();
// 获取我们目标对象的class
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
// 从Advised中根据方法名和目标类获取AOP拦截器执行链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 如果拦截器链为空
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
// 通过反射直接调用执行
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 如果没有发现任何拦截器那么直接调用切点方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
// 将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行处理
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
// 执行拦截器链
retVal = invocation.proceed();
}
// Massage return value if necessary.
// 获取返回类型
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
// 返回值类型错误
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
// 如果目标对象不为空且目标对象是可变的,如prototype类型
// 通常我们的目标对象都是单例的,即targetSource.isStatic为true
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
// 释放目标对象
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
// 线程上下文复位
AopContext.setCurrentProxy(oldProxy);
}
}
}
proceed方法
/**
* 递归获取通知,然后执行
* @return
* @throws Throwable
*/
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 从索引为-1的拦截器开始调用,并按序递增,如果拦截器链中的拦截器迭代调用完毕,开始调用target的函数,这个函数是通过反射机制完成的
// 具体实现在AopUtils.invokeJoinpointUsingReflection方法中
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取下一个要执行的拦截器,沿着定义好的interceptorOrInterceptionAdvice链进行处理
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
// 这里对拦截器进行动态匹配的判断,这里是对pointcut触发进行匹配的地方,如果和定义的pointcut匹配,那么这个advice将会得到执行
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
// 如果不匹配,那么proceed会被递归调用,知道所有的拦截器都被运行过位置
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// 普通拦截器,直接调用拦截器,将this作为参数传递以保证当前实例中调用链的执行
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
Spring源码分析-事务源码分析
一、事务的本质
1. 何为事务管理
** ** 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
** ** 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
** ** **一个逻辑工作单元要成为事务,必须满足所谓的 **ACID
(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。
2. JDBC中的事务管理
** ** 事务的本质我们还是要先来看下JDBC中对事务的处理。首先准备如下两张表[案例讲解以MYSQL为主]
-- MYSQL
CREATE TABLE t_user (
id varchar(30) NOT NULL,
user_name varchar(60) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE t_log (
id varchar(32) DEFAULT NULL,
log varchar(20) DEFAULT NULL
);
** ** 然后创建对应的实体对象
/**
* 用户
*/
public class User implements Serializable {
private static final long serialVersionUID = -5575893900970589345L;
private String id;
private String userName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
/**
* 日志
*/
public class Log implements Serializable {
private static final long serialVersionUID = -5575893900970589345L;
private String id;
private String log;
public Log() {
}
public Log(String id, String log) {
super();
this.id = id;
this.log = log;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLog() {
return log;
}
public void setLog(String log) {
this.log = log;
}
}
** ** 然后我们通过JDBC操作来同时完成添加用户和添加日志的操作。
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try {
// 注册 JDBC 驱动
// Class.forName("com.mysql.cj.jdbc.Driver");
// 打开连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC", "root", "123456");
// 执行查询
stmt = conn.createStatement();
conn.setAutoCommit(false); // 关闭自动提交
// 添加用户信息
String sql = "INSERT INTO T_USER(id,user_name)values(1,'管理员')";
stmt.executeUpdate(sql);
// 添加日志问题
sql = "INSET INTO t_log(id,log)values(1,'添加了用户:管理员')";
stmt.executeUpdate(sql);
conn.commit(); // 上面两个操作都没有问题就提交
} catch (Exception e) {
e.printStackTrace();
// 出现问题就回滚
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
try {
if (stmt != null) stmt.close();
} catch (SQLException se2) {
}
try {
if (conn != null) conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
}
** ** 通过上面的代码我们发下关键的操作有这三个:
3. Spring中的事务管理
** ** 实际工作中我们更多的是结合Spring来做项目的这时我们要满足的情况是这种。
** ** **从上图可以看出我们在Service中是可能调用多个Dao的方法来操作数据库中的数据的,我们要做的就是要保证UserService中的 **addUser()
方法中的相关操作满足事务的要求。在Spring中支持两种事务的使用方式
第一种基于配置文件的方式:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">
<!-- 开启扫描 -->
<context:component-scan base-package="com.dpb.*"></context:component-scan>
<!-- 配置数据源 -->
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="username" value="pms"/>
<property name="password" value="pms"/>
</bean>
<!-- 配置JdbcTemplate -->
<bean class="org.springframework.jdbc.core.JdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!--
Spring中,使用XML配置事务三大步骤:
1. 创建事务管理器
2. 配置事务方法
3. 配置AOP
-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="fun*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- aop配置 -->
<aop:config>
<aop:pointcut expression="execution(* *..service.*.*(..))" id="tx"/>
<aop:advisor advice-ref="advice" pointcut-ref="tx"/>
</aop:config>
</beans>
第二种基于注解的使用方式:
**但是我们需要先开启事务注解的方式。然后在对应的方法头部可以添加 **@Transactional
@Transactional
public void insertUser(User u) {
this.userDao.insert(u);
Log log = new Log(System.currentTimeMillis() + "", System.currentTimeMillis() + "-" + u.getUserName());
this.logDao.insert(log);
}
**当然上面的操作中涉及到了两个概念 **事务的传播属性
和 事务的隔离级别
。参考这两篇文章
传播属性:https://blog.csdn.net/qq_38526573/article/details/87898161
隔离级别:https://blog.csdn.net/qq_38526573/article/details/87898730
二、Spring事务原理
** ** 然后我们来分析下Spring中事务这块的源码实现。
1.Spring事务的源码设计
1.1 事务管理器
** ** 我们来看看事务管理器(PlatformTransactionManager).
TransactionManager:是顶级接口,里面是空的。
public interface TransactionManager {
}
PlatformTransactionManager:平台事务管理器
ReactiveTransactionManager:响应式编程的事务管理器
我们关注的重点是PlatformTransactionManager:
public interface PlatformTransactionManager extends TransactionManager {
/**
获取事务
*/
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
/**
提交数据
*/
void commit(TransactionStatus status) throws TransactionException;
/**
回滚数据
*/
void rollback(TransactionStatus status) throws TransactionException;
}
PlatformTransactionManager也是个接口,在他下面的实现有两个比较重要实现
JtaTransactionManager:支持分布式事务【本身服务中的多数据源】
DataSourceTransactionManager:数据源事务管理器。在但数据源中的事务管理,这个是我们分析的重点。
1.2 事务定义
** ** **然后我们在上面的 **PlatformTransactoinManager
中看到了 TransactionDefinition
这个对象,通过字面含义是 事务定义
。我们来看看结构。
**也就是 **TransactionDefinition
中定义了事务的 传播属性
和 隔离级别
,然后来看看具体的体系结构
DefaultTransactionDefinition:是事务定义的默认实现
DefaultTransactionAttribute:扩展了TransactionAttribute中的属性的实现
**@Transactional:该组件就会被解析加载为对应的 **TransactionDefinition
对象。
1.3 事务的开启
** ** **然后在 **PlatformTransactionManager
中获取事务的时候返回的是 TransactionStatus
对象。我们来看看这个对象。
子类中扩展了
1.4 核心方法讲解
**然后再看看核心的 **getTransaction()
方法
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
// 如果没有事务定义信息则使用默认的事务管理器定义信息
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// 获取事务
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// 判断当前线程是否存在事务,判断依据为当前线程记录的连接不为空且连接中的transactionActive属性不为空
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// 当前线程已经存在事务
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
// 事务超时设置验证
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 如果当前线程不存在事务,但是PropagationBehavior却被声明为PROPAGATION_MANDATORY抛出异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// PROPAGATION_REQUIRED,PROPAGATION_REQUIRES_NEW,PROPAGATION_NESTED都需要新建事务
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
//没有当前事务的话,REQUIRED,REQUIRES_NEW,NESTED挂起的是空事务,然后创建一个新事务
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
// 恢复挂起的事务
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
// 创建一个空的事务
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
关键的方法:doGetTransaction()方法
/**
* 创建一个DataSourceTransactionObject当作事务,设置是否允许保存点,然后获取连接持有器ConnectionHolder
* 里面会存放JDBC的连接,设置给DataSourceTransactionObject,当然第一次是空的
*
* @return
*/
@Override
protected Object doGetTransaction() {
// 创建一个数据源事务对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// 是否允许当前事务设置保持点
txObject.setSavepointAllowed(isNestedTransactionAllowed());
/**
* TransactionSynchronizationManager 事务同步管理器对象(该类中都是局部线程变量)
* 用来保存当前事务的信息,我们第一次从这里去线程变量中获取 事务连接持有器对象 通过数据源为key去获取
* 由于第一次进来开始事务 我们的事务同步管理器中没有被存放.所以此时获取出来的conHolder为null
*/
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
// 非新创建连接则写false
txObject.setConnectionHolder(conHolder, false);
// 返回事务对象
return txObject;
}
然后事务管理的代码
/**
* Create a TransactionStatus for an existing transaction.
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
/**
* 判断当前的事务行为是不是PROPAGATION_NEVER的
* 表示为不支持事务,但是当前又存在一个事务,所以抛出异常
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
/**
* 判断当前的事务属性不支持事务,PROPAGATION_NOT_SUPPORTED,所以需要先挂起已经存在的事务
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 挂起当前事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 创建一个新的非事务状态(保存了上一个存在事务状态的属性)
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
/**
* 当前的事务属性状态是PROPAGATION_REQUIRES_NEW表示需要新开启一个事务状态
*/
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 挂起当前事务并返回挂起的资源持有器
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 创建一个新的非事务状态(保存了上一个存在事务状态的属性)
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 嵌套事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 不允许就报异常
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 嵌套事务的处理
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
// 如果没有可以使用保存点的方式控制事务回滚,那么在嵌入式事务的建立初始简历保存点
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 为事务设置一个回退点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
// 有些情况是不能使用保存点操作
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
最后来看看 startTransaction() 方法
/**
* Start a new transaction.
*/
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
// 是否需要新同步
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建新的事务
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务和连接
doBegin(transaction, definition);
// 新同步事务的设置,针对于当前线程的设置
prepareSynchronization(status, definition);
return status;
}
doBegin方法开启和连接事务
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
// 强制转化事务对象
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 判断事务对象没有数据库连接持有器
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 通过数据源获取一个数据库连接对象
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 把我们的数据库连接包装成一个ConnectionHolder对象 然后设置到我们的txObject对象中去
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 标记当前的连接是一个同步事务
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 为当前的事务设置隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
// 设置先前隔离级别
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 设置是否只读
txObject.setReadOnly(definition.isReadOnly());
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
// 关闭自动提交
if (con.getAutoCommit()) {
//设置需要恢复自动提交
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
// 关闭自动提交
con.setAutoCommit(false);
}
// 判断事务是否需要设置为只读事务
prepareTransactionalConnection(con, definition);
// 标记激活事务
txObject.getConnectionHolder().setTransactionActive(true);
// 设置事务超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
// 绑定我们的数据源和连接到我们的同步管理器上,把数据源作为key,数据库连接作为value 设置到线程变量中
if (txObject.isNewConnectionHolder()) {
// 将当前获取到的连接绑定到当前线程
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
// 释放数据库连接
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
在doBegin方法中核心的关闭了自动提交
同时把连接绑定到本地线程中bindResource方法
2.Spring事务源码串联
2.1 编程式事务
** ** 结合上面的设计我们就可以来实现事务的处理了
@Autowired
private UserDao userDao;
@Autowired
private PlatformTransactionManager txManager;
@Autowired
private LogService logService;
@Transactional
public void insertUser(User u) {
// 1、创建事务定义
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// 2、根据定义开启事务
TransactionStatus status = txManager.getTransaction(definition);
try {
this.userDao.insert(u);
Log log = new Log(System.currentTimeMillis() + "", System.currentTimeMillis() + "-" + u.getUserName());
// this.doAddUser(u);
this.logService.insertLog(log);
// 3、提交事务
txManager.commit(status);
} catch (Exception e) {
// 4、异常了,回滚事务
txManager.rollback(status);
throw e;
}
}
2.2 AOP事务
** ** 上面的案例代码我们可以看到在Service中我们通过事务处理的代码实现了事务管理,同时结合我们前面学习的AOP的内容,我们发现我们完全可以把事务的代码抽取出来,然后我们来看看Spring中这块是如何处理的。
**我们可以通过Debug的方式看到处理的关键流程 **TransactionInterceptor
就是事务处理的 advice
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
进入到invokeWithinTransaction方法中
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 获取我们的事务属性源对象
TransactionAttributeSource tas = getTransactionAttributeSource();
// 通过事务属性源对象获取到当前方法的事务属性信息
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取我们配置的事务管理器对象
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 获取连接点的唯一标识 类名+方法名
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 声明式事务处理
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 创建TransactionInfo
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 执行被增强方法,调用具体的处理逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 异常回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除事务信息,恢复线程私有的老的事务信息
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
//成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// 编程式事务处理
Object result;
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
然后进入到createTransactionIfNecessary方法中
然后进入 getTransaction 这个方法我们前面看过
核心的是doBegin方法。完成 自动提交的关闭和 本地线程 对象的存储
2.3 TransactionInterceptor
** ** 接下来看看TransactionInterceptor是如何注入到容器中的,首先来看看事务的开启@EnableTransactionManagement
一步步进入
可以看到对应的拦截器的注入
然后可以看到拦截器关联到了Advisor中了
到这儿就分析完了