1 什么是循环依赖

  如下,有类A和B,A中有一个类型为B的属性b,B中有一个类型为A的属性a,A和B相互依赖

public class A {

    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public A() {
    }

    public A(B b) {
        this.b = b;
    }
}

 

public class B {

    private A a;

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

    public B() {
    }

    public B(A a) {
        this.a = a;
    }
}

 

public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.setB(b);
        b.setA(a);
    }

  通常,属性的设置可以通过set方法和构造器来完成。我们可以通过set方法来设置。

 

2 spring解决循环依赖的方法概述

  如下图,如果Spring要创建A和B并且对a和b属性赋值,像这样做就陷入了一个死循环。

那么,spring怎么去解开这个环呢?

spring创建对象是分为两大步的,实例化和初始化。

所以,可以先把实例化的A、B先存起来,等需要使用A、B的时候拿过来用。

如下图:我们增加一个缓存。把实例化的对象放进去,要用的时候拿出来就可以了。这样子,这个死循环就解开了。

所以,spring解开循环依赖的问题的关键点就在:实例化和初始化分开在做+缓存完成实例化但未初始化的对象(半成品对象)。

spring的缓存共采用了三级缓存

 

3 spring三级缓存源码(DefaultSingletonBeanRegistry.java)

  我们先看一下三级缓存,他们都是Map。

  一级缓存的value是Object

  二级缓存的value是Object

  三级缓存的value是ObjectFactory

  我们先记住这三个缓存的名称和value

/** Cache of singleton objects: bean name to bean instance. */
  //一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */
   //三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */
  //二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

 不考虑动态代理的话,采用二级缓存就可以解决循环依赖的问题,因为考虑到动态代理的额问题,所以采用了三级缓存

 

4.接下来采用Bebug来看spring解决循环依赖的具体实现

接下来采用Bebug来看spring解决循环依赖的具体实现。在这之前,我们需要先了解spring创建对象的过程:https://www.cnblogs.com/jthr/p/15910423.html

下图我列出创建对象中主要的几个方法,我们主要看这几个方法

 

5 测试准备

5.1 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean id="a" class="com.ruoyi.weixin.user.Test.A">
        <property name="b" ref="b"></property>
    </bean>

    <bean id="b" class="com.ruoyi.weixin.user.Test.B">
        <property name="a" ref="a"></property>
    </bean>
</beans>

 

5.2 测试代码

public class CycleTest {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("cycle.xml");

        A a = ac.getBean(A.class);
        System.out.println(a.getB());

        B b = ac.getBean(B.class);
        System.out.println(b.getA());
    }
}

 

6 Debug运行

下图是A、B两个对象的创建和属性赋值主要的流程图,配合下面的步骤来看

 

7 进入refresh方法

  从ClassPathXmlApplicationContext的构造方法进入refresh方法

 

8 finishBeanFactoryInitialization(beanFactory)方法

  refresh方法中共分为了十三步来处理,我们跳过前面的,直接进入finishBeanFactoryInitialization()方法,这个方法真正的开始进行实例化操作了。

 

9 preInstantiateSingletons方法

跳过finishBeanFactoryInitialization方法中一系列的设置,一直到beanFactory.preInstantiateSingletons()方法
这个方法就是开始实例化剩余的所有的非懒加载的对象,进去这个方法,从preInstantiateSingletons这个方法开始,正儿八经的开始实例化了
我们共有两个对象需要实例化,我们看beanNames集合,里面有两个元素a和b, 接下来,会循环beanNames这个集合来创建对象

 

10 我们进入循环,查看对象的创建的主要过程,按照下图的方法来看



11 进入循环后,一步步往下走,会看到getBean方法

 

12 进入getBean方法,会看到doGetBean方法

 

13 getSingleton-从缓存中获取实例

   进入dogetbean方法,我们会看到它调用了getSingleton方法,这个方法就是会缓存中获取

 

14 进入getSingleton方法

  进入getSingleton

   再进入getSingleton方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
     //从单例对象缓存(一级缓存)中获取缓存的单例对象
Object singletonObject = this.singletonObjects.get(beanName);
      //如果没有,并且该beanName对应的单例bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        //从早期单例对象缓存(二级缓存)中获取早期单例对象(之所以称为早期单例对象,是因为里面的对象都是通过提前曝光的ObjectFactory创建出来的,还没有进行属性填充等操作) singletonObject
= this.earlySingletonObjects.get(beanName);
        //如果早期单例对象缓存(二级缓存)中也没有,并且允许创建早期单例对象应用
if (singletonObject == null && allowEarlyReference) {
          //锁定全局变量并进行处理 synchronized (
this.singletonObjects) { // Consistent creation of early reference within full singleton lock
            
singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null) {
                  //当某些方法需要提前初始化的时候会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactory(三级缓存) ObjectFactory
<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) {
                    //如果存在单例对象工厂,则通过工厂创建一个单例对象 singletonObject
= singletonFactory.getObject();
                    //存储在二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
                    //从三级缓存中移除
this.singletonFactories.remove(beanName); } } } } } } return singletonObject; }

  此时先去以及缓存中查找a对象,不存在

  进入if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) 判断,这个判断是a对象不为空,并且a对象正在创建中时为true。由于现在只是在查找是否存在a对象,还没有开始创建a对象,所以判定为false,不会进去。直接返回一个null

 

15 再次回到getBean方法

  Object sharedInstance = getSingleton(beanName);获取的是null

 

16 继续往下走

  再次看到了getSingleton方法,这里传入的是一个函数式接口(lamada表达式)

 

17 进入getSingleton方法

  我们看到这个方法有两个参数:beanName和ObjectFactory。所以上面传入的函数式接口(lamada)就是ObjectFactory的实现

  我们查看ObjectFactory,发现它就只有一个方法getObject

@FunctionalInterface
public interface ObjectFactory<T> {

    /**
     * Return an instance (possibly shared or independent)
     * of the object managed by this factory.
     * @return the resulting instance
     * @throws BeansException in case of creation errors
     */
    T getObject() throws BeansException;

}

  接种往下走,我们会看到以下调用,它实际上调用的就是刚才传入的函数式接口(lamada表达式),里面调用了createBean方法

singletonObject = singletonFactory.getObject();

 

18 进入singletonFactory.getObject(),开始执行createBean方法

  再进入createBean方法

 

19 进入createbean方法

  跳过前面的一系列逻辑判断,到达doCreateBean方法

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

 

20 进入doCreateBean方法,到达createBeanInstance方法

  跳过前面的逻辑判断,到达createBeanInstance方法,这个方法会创建对象

instanceWrapper = createBeanInstance(beanName, mbd, args);

执行完这个方法,我们会看到A对象已经创建了A@1892

  且此时a对象里面的b属性是空的,所以此时a对象是个半成品

 

 

21 addSingletonFactory

  接着往下走,到达addSingletonFactory方法,这个方法传入两个参数,beanName和一个函数式接口(lamada表达式)

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

进入addSingletonFactory方法,这个方法两个参数beanName和ObjectFactory,所以刚才传入的函数式接口(lamada)是ObjectFactory的实现


protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
  //使用singletonObjects加锁,保证线程安全 synchronized (
this.singletonObjects) {
    //如果一级缓存中没有beanName对象
if (!this.singletonObjects.containsKey(beanName)) {
      //将beanName:ObjectFactory放入三级缓存中
this.singletonFactories.put(beanName, singletonFactory);
      //移除二级缓存中的beanName对象
this.earlySingletonObjects.remove(beanName);
      //将beanName添加到已注册的单例集中
this.registeredSingletons.add(beanName); } } }

  往下执行,现在以及缓存中没有a对象,将beanName:ObjectFactory(也就是那个函数式接口)放入三级缓存中,这里放入三级缓存的是ObjectFactory而不是a对象

22 执行完addSingletonFactory回到doCreateBean继续执行,来到populateBean方法

//对bean的属性进行填充,将各个属性注入,其中,可能存在依赖其他bean的属性,那么会递归创建依赖的bean
populateBean(beanName, mbd, instanceWrapper);

 

23 进入populate方法,找到applyPropertyValues方法

  跳过前面的一系列处理,来到最后一行applyPropertyValues方法,这个方法对属性进行填充

applyPropertyValues(beanName, mbd, bw, pvs);

  进入applyPropertyValues方法,往下来之来到一下代码处

//获取属性名称
String propertyName = pv.getName();
//获取未经类型转换的值 Object originalValue
= pv.getValue(); if (originalValue == AutowiredPropertyMarker.INSTANCE) {
 //获取preopertyName的setter方法 Method writeMethod
= bw.getPropertyDescriptor(propertyName).getWriteMethod();

我们看到这里获取的originalValue是一个RuntimebeanReference对象

 

24 接着往下走来到resolveValueIfNecessary方法

//交由valueResolver根据pv解析出originalValue(RuntimebeanReference)所封装的对象
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

  进入resolveValueIfNecessary方法,这个判断为true,调用resolveReference方法,解析封装的对象

if (value instanceof RuntimeBeanReference) {
            RuntimeBeanReference ref = (RuntimeBeanReference) value;
        //解析出ref(RuntimeBeanReference)封装的bean元信息的bean对象
return resolveReference(argName, ref); }

 

25 进入resolveReference方法

  进入resolveReference方法往下走,来到下面代码

//resolvedName=ref保证的bean的名称
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
//获取resolvedName的bean对象
bean = this.beanFactory.getBean(resolvedName);

 这里又回到了getBean方法,不过这里查找的是b对象,为了给a对象的b属性赋值

 

26 又回到了getBean方法,这里针对的额是b对象

  和a对象一样的步骤,12到20步走下来,创建了b对象b@1736

 

 

 

 

27 创建了b对象后,需要对b进行属性填充

  和a的步骤一样,接着20步走到25步,又回到了getBean方法,此时去获取的是a对象(为了给b对象的a属性赋值)

 

28 又回到getBean方法,走到getSingleton

  和 12 13步一样,来到getSingleton-从缓存中获取实例方法,从缓存中去获取a对象

   进入getSingleton方法

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // Quick check for existing instance without full singleton lock
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized (this.singletonObjects) {
                    // Consistent creation of early reference within full singleton lock
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }

从一级缓存获取a对象不存在

进入下面的判断,此时a正在创建中,所以判断为true,进入

 

从二级缓存中获取a对象,还是没有

 

 

 

 

 通过singletonObjects加锁

再次判断一级缓存和二级缓存是否存在a对象,还是没有

从三级缓存中获取singletonFactory对象。前面我们已经在三级缓存中存入了两个singletonFactory对象(函数式编程lamada表达式)

 

接着调用singletonFactory.getObject()

进入getObject,实际上调用的是我们传入的lamada表达式getEarlyBeanReference方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

执行完成得到a对象

 再把a对象(还是个半成品,b属性没有值)放入二级缓存

this.earlySingletonObjects.put(beanName, singletonObject);

再从三级缓存中移除a的singletonFactory对象

this.singletonFactories.remove(beanName);

29 接着往下走,回到applyPropertyValues方法

  继续往下执行,到达下面代码,给b对象的a属性赋值

bw.setPropertyValues(new MutablePropertyValues(deepCopy));

 

30 继续执行

  继续往下执行,执行完applyPropertyValues,执行完populateBean(beanName, mbd, instanceWrapper)回到了doCreateBean方法中

  此时,看b对象中的a属性已有值了,但是a里面b属性还没有值

 

31 继续往下执行,一直回到getSingleton方法

  在该方法中继续往下执行,来到下面代码,addSingleton方法

if (newSingleton) {
   addSingleton(beanName, singletonObject);
  }

  进入addSingleton方法

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
        //一级缓存中存入对象
this.singletonObjects.put(beanName, singletonObject);
        //三级缓存中移除对象
this.singletonFactories.remove(beanName);
        //二级缓存中移除对象
this.earlySingletonObjects.remove(beanName);
        //将beanName添加到已注册单例集中
this.registeredSingletons.add(beanName); } }

  将完整的b对象(a属性有值)存入一级缓存,再将二级、三级缓存中的b对象移除

 

 

32 继续往下走

  刚才创建b对象时为了给a对象的b属性赋值,现在b对象有了,该给a对象的b属性赋值了

  继续往下走,回到applyPropertyValues方法

  再次执行bw.setPropertyValues(new MutablePropertyValues(deepCopy));

  此时给a对象里面的b属性赋值

 

33 继续执行

  执行完applyPropertyValues,一直回到doCreateBean方法,populateBean方法执行完成

  

   此时a对象的b属性有值了

 

34 重复第31部

   继续往下执行,一直回到getSingleton方法

  在该方法中继续往下执行,来到下面代码,addSingleton方法

if (newSingleton) {
   addSingleton(beanName, singletonObject);
  }

  进入addSingleton方法

protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
        //一级缓存中存入对象 this.singletonObjects.put(beanName, singletonObject);
        //三级缓存中移除对象 this.singletonFactories.remove(beanName);
        //二级缓存中移除对象 this.earlySingletonObjects.remove(beanName);
        //将beanName添加到已注册单例集中 this.registeredSingletons.add(beanName); } }

  将完整的a对象(b属性有值),再将二级、三级缓存中的a对象移除

 

 

 

 此时,我们a、b对象,a中有b,b中有a

 

35 继续往下走,回到preInstantiateSingletons方法

  此时a、b对象都已创建

  所以,在下面这个循环中,不会再去创建b对象,而是直接获取到b对象

 

  到此,a、b创建完成,且成功解套