Spring源码剖析(二) - Bean对象的三级缓存

前面讲到Spring在创建Bean的过程中使用了三级缓存来对Bean对象进行缓存。这个三级缓存是用来解决对象的循环依赖问题。

什么是对象的循环依赖?

举个例子:

class A {
  private B b;
  private C c;
}

class B {
  private A a;
}

class C {
  private A a;
}

class A中引用了B和C,而B和C中又引用了A。
那么在spring中创建Bean对象时,需要先创建对象,然后对其属性进行填充。当对A进行属性填充时,发现需要创建B和C,而在创建B和C时,又发现需要创建A。此时就出现了循环依赖问题了。

怎么解决循环依赖?

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    /** Cache of singleton objects: bean name to bean instance. */
    private final Map singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name to ObjectFactory. */
    private final Map> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance. */
    private final Map earlySingletonObjects = new HashMap<>(16);

spring利用singletonObjects, earlySingletonObjects, singletonFactories三级缓存去解决的。


spring2.png

我们假设现在有这样的场景AService依赖BService,BService依赖AService:
1. AService首先实例化,实例化通过ObjectFactory半成品暴露在三级缓存中
2. 填充属性BService,发现BService还未进行过加载,就会先去加载BService
3. 再加载BService的过程中,实例化,也通过ObjectFactory半成品暴露在三级缓存
4. 填充属性AService的时候,这时候能够从三级缓存中拿到半成品的ObjectFactory。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

拿到ObjectFactory对象后,调用ObjectFactory.getObject()方法最终会调用getEarlyBeanReference()方法。

getEarlyBeanReference这个方法主要逻辑大概描述下如果bean被AOP切面代理则返回的是beanProxy对象,如果未被代理则返回的是原bean实例,这时我们会发现能够拿到bean实例(属性未填充),然后从三级缓存移除,放到二级缓存earlySingletonObjects中,而此时B注入的是一个半成品的实例A对象,不过随着B初始化完成后,A会继续进行后续的初始化操作,最终B会注入的是一个完整的A实例,因为在内存中它们是同一个对象。

为什么是三级缓存?

一般情况下二级缓存已经足够解决循环依赖,但是如果遇到AOP的情况下,一个Bean需要被代理,这时二级缓存就无法解决了。

假设上面的AService配置了AOP,那么singletonFactory.getObject()返回的是一个AService的代理对象。因为AService是单例的,每次执行singleFactory.getObject()方法又会产生新的代理对象,假设这里只有一级和三级缓存的话,我每次从三级缓存中拿到singleFactory对象,执行getObject()方法又会产生新的代理对象,这是不行的,因为AService是单例的。

所有这里我们要借助二级缓存来解决这个问题,将执行了singleFactory.getObject()产生的对象放到二级缓存中去,后面去二级缓存中拿,没必要再执行一遍singletonFactory.getObject()方法再产生一个新的代理对象,保证始终只有一个代理对象。

你可能感兴趣的:(Spring源码剖析(二) - Bean对象的三级缓存)