Spring循环依赖与三级缓存

    技术2022-07-10  137

    一、什么是循环依赖。

    现在有A类和B类,A持有B的引用,B持有A的引用,这就是循环依赖。如果没有Spring,我们又是如何去解决循环依赖呢。

    @Test public void testCircle() throws Exception { TestA a = new TestA(); TestB b = new TestB(); b.setTestA(a); a.setTestB(b); }

    二、Spring实现循环依赖原理

    spring解决循环依赖也是如此,首先暴露一个未初始化的实例TestA放到缓存中,创建TestB的实例时,获取的是TestA的未初始化对象,TestB创建完成以后,将TestA进行初始化,由于TestB中TestA的引用和TestA是一样的,TestB中的属性也是完全的初始化的。

    三、Spring的三级缓存

    DefaultSingletonBeanRegistry中存在三个Map,用作三级缓存。 一级缓存:singletonObjects ,用于保存BeanName与创建bean实例。 二级缓存:earlySingletonObjects ,用于BeanName与创建bean实例,与singletonObjects 不同的是earlySingletonObjects 中存放的bean是一个未初始化的bean。 三级缓存:singletonFactories ,用于存放BeanName与bean工厂。

    /** Cache of singleton objects: bean name --> bean instance */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256); /** Cache of singleton factories: bean name --> ObjectFactory */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); /** Cache of early singleton objects: bean name --> bean instance */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

    四、如何去实现

    从源码去解释这一段,创建Bean的方法核心步骤在AbstractBeanFactory类的doGetBean方法中,大致分为三阶段:实例化,填充(属性),初始化。 其中getSingleton方法被多次调用,它是一个重载方法。在创建bean之前,都会先去从缓存中获取,如果没有获取到,则创建以后放入缓存中,这种方式是非常惯用的。

    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 != NULL_OBJECT ? singletonObject : null); }

    以上代码很容易理解,分别尝试从一级,二级,三级缓存中获取BeanName对应的bean,如果三级缓存中有,则将三级缓存中的对象放到二级缓存中,清除三级缓存。

    在初次加载TestA对象时,缓存中是没有任何TestA的bean对象。需要去创建一个TestA的bean,在创建之前,需要对bean进行标记(正在创建,防止重复创建)。这时也会用到getSingleton方法去创建TestA的实例。

    // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { 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); }

    在TestA完全创建以后会放到一级缓存中,同时清空二三级缓存。

    */ protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT)); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }

    在TestA进行实例化完成以后,将TestA对应的ObectFactory放入三级缓存中,然后填充TestA的属性,这时候发现持有TestB的引用,进而创建TestB的bean(重复TestA的创建过程),TestB进行属性填充时会去从缓存中获取TestA的bean,此时的TestA是一个未初始化半成品存在于三级缓存中,当TestB属性填充完成以后,会从将TestB的bean放入一级缓存中,并从二三级缓存中删除TestB。继续填充TestA,并完成初始化后将TestA的bean放入一级缓存中,并从二三级缓存中删除TestA。

    有一个值得注意的地方时,在创建普通bean(没有代理)的时候,二三级缓存其实没区别。

    // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); }

    这个匿名内部类ObjectFactory就是三级缓存中的值,用于获取被代理后的bean,没有进行代理时,二级缓存与三级缓存就是一样的。

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

    在多线程环境下创建bean的过程,使用三级缓存是非常有必要的事情。

    Processed: 0.014, SQL: 9