Skip to content

Latest commit

 

History

History
111 lines (64 loc) · 3.62 KB

初探Spring源码,完成刷新阶段(6).md

File metadata and controls

111 lines (64 loc) · 3.62 KB

文章内容如有错误,欢迎指出

在上一章,已经了解了后置处理的一些知识,以及了解到main函数上面的那些spring注解初始化过程。也了解到beanFactoryPostProcess是怎么一个大致工作流程

那么这一章,将去了解bean实例化过程

由于自己已经提前看了很多遍代码。发现如果要全部贴上来的话,非常影响阅读。同时贴太多的代码也不容易记得调用过程。

所以从这章开始,贴代码的会比较少。着重记录一些阅读源码的简单过程和心得。

本章主要了解两个问题

1.bean的实例化过程(getBean()

2.三级缓存(其实看了几遍代码没确定它的实质性作用,更想定义为如何解决循环依赖)

那么直接开干

先看一下java的循环依赖

public class JavaBeanA {
    JavaBeanB beanB;

    public JavaBeanA(JavaBeanB beanB) {
        this.beanB = beanB;
    }
}
public class JavaBeanB {
    private JavaBeanA javaBeanA;

    public JavaBeanB(JavaBeanA javaBeanA) {
        this.javaBeanA = javaBeanA;
    }
}
public class CycleTest {
    public static void main(String[] args) {
        JavaBeanA javaBeanA = new JavaBeanA(new JavaBeanB(new JavaBeanA())); //这里因为JavaBeanA/JavaBeanB类只有一个构造方法,根本没有办法实例化。 所以这里会编译报错
        System.out.println(javaBeanA);
    }
}

目前能解决编译报错的方式只能不在构造器里面传入JavaBeanB

随后我们验证一下,在spring框架下能否解决这个情况

spring循环依赖

显然,spring也没有办法处理构造器循环依赖

spring是如何开始处理 A类里面有成员属性B , B类里面有成员属性A的呢?

spring找到创建bean位置

或者直接跳到方法org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

image-20220308113318882

创建条件断点1(org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

spring找到创建bean位置2

创建条件断点2(org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

3。开始调试

spring处理成员变量循环依赖

4.结论

当通过org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons实例化所有bean的时

  • 对bean做反射,生成唯一对象。
  • 处理成员变量 (org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties)
  • 在处理成员变量时。会递归调用getBean()方法。也就是如果A bean在创建完成之后。会把b也给创建出来

中间省略了一些过程。

确实没有发现循环依赖有什么特别之处。

spring的解决办法也很简单。只需要把beanName放到一个Set集合里面(参考org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#beforeSingletonCreation)。

大致如下:

if (!this.inCreationCheckExclusions.contains(beanName) //this.inCreationCheckExclusions.contains(beanName)是false , 加 ! 就是true
    &&   !this.singletonsCurrentlyInCreation.add(beanName)) { //set集合增加元素。增加失败 的话就是false .如果增加失败就会抛异常
			throw new BeanCurrentlyInCreationException(beanName);
		}

可能还有一些没有关注到的点。毕竟每个细节都注意的话。spring将是一个庞大的工程。