spring史上最详细源码解析系列--循环依赖

spring的循环依赖可以暴露出很多关键的问题。可以纠正市面上几个理解的不对的地方:

  • AOP执行时间并不都是在spring执行完生命周期回调执行,当发生循环依赖的时候在提前暴露的工厂getObject的时候进入getEarlyBeanReference(beanName, mbd, bean)已经提前完成AOP了

这篇文章适合已经读过spring源码的读者看,因为很多流程我这里不会提到,当然后续会继续更新spring的整个流程。话不多说,开始咯!!

应用代码

Appconfig.java类的代码
@Configuration
@ComponentScan("org.debug")
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class AppConfig {


//  @Bean
//  public Ca createCa(){
//      System.out.println("init ca");
//      return new Ca();
//  }
//
//  @Bean
//  public Cb createCb(){
//      System.out.println("init cb");
//      createCa();
//      return new Cb();
//  }
}
A.java类的代码
@Component
public class A {

    @Autowired
    private C c;

    public A(){
        System.out.println("A被创建 了");
    }

    public void executor(){
        System.out.println("A executor");
    }
}
C.java类的代码
@Component
//@Scope("prototype")
public class C {

    @Autowired
    private A a;

    public C() {
        System.out.println("C呗创建");
    }

    public void executor(){
        System.out.println("C executor");
    }
}

这两个类非常简单,就是相互引用了对方,也就是我们常常的说的循环依赖,spring是允许这样的循环依赖(前提是单例的情况下的,非构造方法注入的情况下,还有开启循环依赖的情况,当然spring默认是开启的)

运行结果图

读者只要看上面圈起来的红色的就可以了,已经可以证明spring是支持循环依赖的。

下图是我修改spring源码让它不支持循环依赖

那么为什么setAllowCircularReferences(false);会关闭循环依赖呢?首要明白spring的循环依赖是怎么做到的呢?spring源码当中是如何处理循环依赖的? 分析一下所谓的循环依赖其实无非就是属性注入,或者就是大家常常说的自动注入, 故而搞明白循环依赖就需要去研究spring自动注入的源码;spring的属性注入属于spring bean的生命周期一部分;怎么理解spring bean的生命周期呢?后面我会继续说,不会在本文中说明。
要理解bean的生命周期首先记住两个概念
请读者一定记住两个概念——spring bean和对象:

  • spring bean——受spring容器管理的对象,可能经过了完整的spring bean生命周期(为什么是可能?难道还有bean是没有经过bean生命周期的?答案是有的,具体我们后面文章分析),最终存在spring容器当中;一个bean一定是个对象
  • 对象——任何符合java语法规则实例化出来的对象,但是一个对象并不一定是spring bean;

所谓的bean的生命周期就是磁盘上的类通过spring扫描,然后实例化,跟着初始化,继而放到容器当中的过程

上图就是spring容器初始化bean的大概过程(至于详细的过程,后面文章再来介绍);
文字总结一下:
1:实例化一个ApplicationContext的对象;
2:调用bean工厂后置处理器完成扫描;
3:循环解析扫描出来的类信息;
4:实例化一个BeanDefinition对象来存储解析出来的信息;
5:把实例化好的beanDefinition对象put到beanDefinitionMap当中缓存起来,以便后面实例化bean;
6:再次调用bean工厂后置处理器;
7:当然spring还会干很多事情,比如国际化,比如注册BeanPostProcessor等等,如果我们只关心如何实例化一个bean的话那么这一步就是spring调用finishBeanFactoryInitialization方法来实例化单例的bean,实例化之前spring要做验证,需要遍历所有扫描出来的类,依次判断这个bean是否Lazy,是否prototype,是否abstract等等;
8:如果验证完成spring在实例化一个bean之前需要推断构造方法,因为spring实例化对象是通过构造方法反射,故而需要知道用哪个构造方法;
9:推断完构造方法之后spring调用构造方法反射实例化一个对象;注意我这里说的是对象、对象、对象;这个时候对象已经实例化出来了,但是并不是一个完整的bean,最简单的体现是这个时候实例化出来的对象属性是没有注入,所以不是一个完整的bean;
10:spring处理合并后的beanDefinition
11:判断是否支持循环依赖,如果支持则提前把一个工厂存入singletonFactories——map;
12:判断是否需要完成属性注入
13:如果需要完成属性注入,则开始注入属性
14:判断bean的类型回调Aware接口
15:调用生命周期回调方法
16:如果需要代理则完成代理
17:put到单例池——bean完成——存在spring容器当中

大概了解下整个过程,后面文章会详细分析,当前先进行循环依赖的分析。

源码分析

流程图

先看下循环依赖流程图,大概有个映象:

找到解决循环依赖源码所在
  • refresh方法当中调用finishBeanFactoryInitialization方法来实例化所有扫描出来的类
  • preInstantiateSingletons方法经过一系列判断之后会调用getBean方法去实例化扫描出来的类
  • getBean方法就是个空壳方法,调用了doGetBean方法

doGetBean方法内容有点多,这个方法非常重要,不仅仅针对循环依赖,
甚至整个spring bean生命周期中这个方法也有着举足轻重的地位,当然本文会对它解决循环依赖部分进行分析。需要说明的是我为了更好的说清楚这个方法,下面重点说这个doGetBean方法。

protected  T doGetBean(final String name, @Nullable final Class requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    

    //transformedBeanName(name)这里的name就是bean的名字,先这样理解 当然实际上不仅如此
   final String beanName = transformedBeanName(name);
   //定义了一个对象,用来存将来返回出来的bean
   Object bean;
   //现在我们循环依赖的场景是A类注入C,发现C类不在容器,则去创建C,创建完C要注入A属性,发现A不在容器,去创建A,可以整体分为几部。
    //1.实例化A对象 2.往A对象注入C属性 3.创建C对象 4.往C对象注入A属性  5.A此时不在单例池所以去创建A,但是这时候
    //调用getSingleton(beanName, true)判断的时候已经包含在这个正在创建的单例池this.singletonsCurrentlyInCreation.contains(beanName)。
    //而且allowEarlyReference又是允许为true,这个时候它根据beanName去拿到提前暴露的工程,调用getObject,则这时候如果有代理的
    //话,就会去执行代理,这样才是一个完整的A,假如一开始没提前暴露工厂,而是只是一个不完整的对象,最终注入也是不完整的。
    //最后把这个完整的bean存储,this.earlySingletonObjects.put(beanName, singletonObject);
    //然后返回这个完成代理的bean(如果没有AOP,则也不会是个代理bean),返回bean注入到C。
    //C注入完毕开始执行生命周期回调和最后一个beanPostProcessor完成AOP设置
    //然后返回Cbean,A注入C,完成循环依赖。
    //这边getSingleton第一次调用的时候啥时候都不做,然后进入下面的sharedInstance = getSingleton(beanName, () -> {,
    //会做一件重要的事,this.singletonsCurrentlyInCreation.add(beanName)。然后用addSingletonFactory提前暴露工厂this.singletonFactories.put(beanName, singletonFactory);
    //这样第二次再调getSingleton(beanName, true)才有了获取提前暴露的工厂,调用getObject。
    Object sharedInstance = getSingleton(beanName);
    
    
  /**
   * 如果sharedInstance不等于空直接返回
   * 当然这里没有直接返回而是调用了getObjectForBeanInstance
   * 关于这方法以后解释,读者可以认为这里可以理解为
   * bean =sharedInstance; 然后方法最下面会返回bean
   * 什么时候不等于空?
   * 再容器初始化完成之后
   * 程序员直接调用getbean的时候不等于空
   * 什么时候等于空?
   * 上文已经解释过了,创建对象的时候调用就会等于空
   */  
   if (sharedInstance != null && args == null) {
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
     
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }else{
          /**
           * 需要说明的笔者删了很多和本文无用的代码
           * 意思就是源码中执行到这个if的时候有很多其他代码
           * 但是都是一些判断,很本文需要讨论的问题关联不大
           * 这个if就是判断当前需要实例化的类是不是单例的
           * spring默认都是单例的,故而一般都成立的
           * 接下来便是调用第二次 getSingleton
           * 第二次会把当前正在创建的类记录到set集合
           * 然后反射创建这个实例,并且走完生命周期
           **/
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  //完成了目标对象的创建
                  //如果需要代理,还完成了代理
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  // Explicitly remove instance from singleton cache: It might have been put there
                  // eagerly by the creation process, to allow for circular reference resolution.
                  // Also remove any beans that received a temporary reference to the bean.
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
   return (T) bean;
}

提前暴露工厂,在实例化好对象,还没注入属性的时候添加的

             //循环依赖的条件必须bean是单例支持循环依赖,并且这个bean当前正在创建中
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isTraceEnabled()) {
                logger.trace("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            //解决循环依赖,addSingletonFactory会提前暴露bean工厂
            //而() -> getEarlyBeanReference(beanName, mbd, bean)需要这个暴露的bean工厂去getObject
            //如果你开启@EnableAspectJAutoProxy则这里会多了一个后置处理器,AnnotationAwareAspectJAutoProxyCreator
            //处理代理逻辑
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
        }
protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                //提前暴露一个bean工厂,为后面解决循环依赖,这个工程是jdk为调用者生成的代理,
                //假如从AbstractAutowireCapableBeanFactory调过来,则singletonFactory是AbstractAutowireCapableBeanFactory$lambda@1583
                //那这个真正有意义的时候是调用singletonFactory.getObject的时候,就会去触发() -> getEarlyBeanReference(beanName, mbd, bean)
                //而() -> getEarlyBeanReference(beanName, mbd, bean)这段会去触发后置处理器完成各种事情
                //所以这里只是埋下伏笔
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }

这个方法主要是循环依赖的时候提前去完成AOP代理会调用

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            //开天辟地六个后置处理器
            //ApplicationContextAwareProcessor
            //ConfigurationClassPostProcessor
            //PostProcessorRegistrationDelegate
            //CommonAnnotationBeanPostProcessor
            //AutowireAnnotationBeanPostProcessor
            //ApplicationListenerDetector
            //如果开启了AOP,则会多了个AnnotationAwareAspectJAutoProxyCreator,其实这里最重要是这个,这里就是要完成AOP代理的
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

大家喜欢的点个赞,关注下我,后续会继续更新spring的完整源码分析哦!!!!!!

你可能感兴趣的:(spring史上最详细源码解析系列--循环依赖)