咱们都晓得Spring为了解决循环依赖应用了三级缓存
Spring三级缓存
一级缓存singletonObjects
用于保留BeanName和创立bean实例之间的关系,beanName -> bean instance
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
二级缓存earlySingletonObjects
保留提前曝光的单例bean对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
三级缓存singletonFactories
保留beanName和创立bean实例之间的关系,与singletonObjects不同的中央在于,当一个单例bean被放到这外面后,bean在创立过程中,能够通过getBean办法获取到,目标是用来检测循环援用
private final Map<String, Object> singletonFactories = new HashMap(16);
在创立bean的时候,首先从缓存中获取单例的bean,这个缓存就是singletonObjects,如果获取不到且bean正在创立中,就再从earlySingletonObjects中获取,如果还是获取不到且容许从singletonFactories中通过getObject拿到对象,就从singletonFactories中获取,如果获取到了就存入earlySingletonObjects并从singletonFactories中移除。
为什么要应用三级缓存?
一级缓存
首先咱们看看一级缓存行不行,如果只留第一级缓存,那么单例的Bean都存在singletonObjects 中,Spring循环依赖次要基于Java援用传递,当获取到对象时,对象的field或者属性能够延后设置,实践上能够,然而如果延后设置出了问题,就会导致残缺的Bean和不残缺的Bean都在一级缓存中,这个援用时就有空指针的可能,所以一级缓存不行,至多要有singletonObjects 和earlySingletonObjects 两级。
两级缓存
那么咱们再看看两级缓存行不行
当初有A的field或者setter依赖B的实例对象,同时B的field或者setter依赖了A的实例,A首先开始创立,并将本人裸露到 earlySingletonObjects 中,开始填充属性,此时发现自己依赖B的属性,尝试去get(B),发现B还没有被创立,所以开始创立B,在进行属性填充时初始化A,就从earlySingletonObjects 中获取到了实例化但没有任何属性的A,B拿到A后实现了初始化阶段,将本人放到singletonObjects中,此时返回A,A拿到B的对象持续实现初始化,实现后将本人放到singletonObjects中,由A与B中所示意的A的属性地址是一样的,所以A的属性填充完后,B也获取了A的属性,这样就解决了循环的问题。
仿佛完满解决,如果就这么应用的话也没什么问题,然而再加上AOP状况就不同了,被AOP加强的Bean会在初始化后代理成为一个新的对象,也就是说:
如果有AOP,A依赖于B,B依赖于A,A实例化实现裸露进来,开始注入属性,发现援用B,B开始实例化,应用A裸露的对象,初始化实现后封装成代理对象,A再将代理后的B注入,再做代理,那么代理A中的B就是代理后的B,然而代理后的B中的A是没用代理的A。
显然这是不对的,所以在Spring中存在第三级缓存,在创建对象时判断是否是单例,容许循环依赖,正在创立中,就将其从earlySingletonObjects中移除掉,并在singletonFactories放入新的对象,这样后续再查问beanName时会走到singletonFactory.getObject(),其中就会去调用各个beanPostProcessor的getEarlyBeanReference办法,返回的对象就是代理后的对象。
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { // Eagerly cache singletons to be able to resolve circular references // 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, () -> getEarlyBeanReference(beanName, mbd, bean)); } /** * Add the given singleton factory for building the specified singleton * if necessary. * <p>To be called for eager registration of singletons, e.g. to be able to * resolve circular references. * @param beanName the name of the bean * @param singletonFactory the factory for the singleton object */ protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }