源码分析:Spring如何解决单例Bean的循环依赖?
Spring如何解决单例Bean的循环依赖?
首先看下DefaultSingletonBeanRegistry的getSingleton(String, boolean)这个方法在Spring中如何获取单例Bean的?
举例说明:
假设Bean为A,第一次对A进行依赖查找时是查不到beanName对应实例的,因为● singletonObjects:不存在A对应元素,A完全初始化之后才会放进去。● singletonsCurrentlyInCreation:也不存在A对应元素!用以标识创建中的状态!
看下这个getSingleton(String beanName, boolean allowEarlyReference)方法:
//DefaultSingletonBeanRegistry.java /** 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 HashMap<>(16); /** Set of registered singletons, containing the bean names in registration order. */ private final Set<String> registeredSingletons = new LinkedHashSet<>(256); /** Names of beans that are currently in creation. */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));/** * Return the (raw) singleton object registered under the given name. * <p>Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */@Nullableprotected 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); //下次进入时singletonObject已经提前暴漏则跳过下边逻辑直接返回。 if (singletonObject == null && allowEarlyReference) { //返回提前暴漏的Bean。之所以能解决循环依赖,就是其他Bean依赖当前BeanA的时候, //singletonFactories返回了A的beanName关联的ObjectFactory, //而这个ObjectFactory#getObject()可以提前暴漏未完全初始化的Bean A实例,其实是一个 //BeanWrapper对象,尚未填充属性和初始化Bean。 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject;}
所以第一次执行上述代码中的getSingleton时,其实返回的shareInstance为null,也就是下边doGetBean中的shareInstance。(这里忽略一些无关代码)假使代码执行到
getSingleton(String beanName,
ObjectFactory<?> objectFactory)
//AbstractBeanFactory.javaprotected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { .... Object sharedInstance = getSingleton(beanName, true); ..... // Create bean instance. 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 bean;}
通过代码细节看到singleObjects中找不到beanName对应的实例,于是后边会根据singletonFactory.getObject()来查找Bean。
singletonFactory就是上述代码中传进来的包含createBean的lambda表达式。
但在createBean表达式执行之前,需要做一些前置准备。也就是执行这个:
beforeSingletonCreation(String beanName);
此方法中执行的操作就是“标志A这个Bean在创建中”,即
singletonsCurrentlyInCreation.add(String BeanName)
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }}
//DefaultSingletonBeanRegistry.javapublic Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { .... synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { ... //this.singletonsCurrentlyInCreation.add(beanName) 标志A这个Bean在创建中 beforeSingletonCreation(beanName); ... try { //AbstractAutowireCapableBeanFactory#createBean singletonObject = singletonFactory.getObject(); newSingleton = true; }catch(...){} finally{ ... //this.singletonsCurrentlyInCreation.remove(beanName) afterSingletonCreation(beanName); } if (newSingleton) { // addSingleton代码贴在这里,方便查看 // protected void addSingleton(String beanName, Object singletonObject) { // synchronized (this.singletonObjects) { // this.singletonObjects.put(beanName, singletonObject); // this.singletonFactories.remove(beanName); // this.earlySingletonObjects.remove(beanName); // this.registeredSingletons.add(beanName); // } // } addSingleton(beanName, singletonObject); } } return singletonObject; }}
创建完Bean以后,即createBean方法执行完毕之后,在finally块中就删除掉Bean A创建中的标识了,即:
afterSingletonCreation(beanName);
实际就是下面这一行代码起了作用:
this.singletonsCurrentlyInCreation.remove(beanName)**
Bean A创建完了,但还需要执行下边操作:
if (newSingleton) { addSingleton(beanName, singletonObject); }
这个操作的作用是更新Bean在Spring容器中的缓存状态。
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { //缓存Bean this.singletonObjects.put(beanName, singletonObject); //删除beanName关联的用以提前暴漏Bean的ObjectFactory this.singletonFactories.remove(beanName); //删除早期暴漏bean缓存标识 this.earlySingletonObjects.remove(beanName); //注册为单例Bean this.registeredSingletons.add(beanName); } }
在createBean中执行Bean A实例化的主要就是doCreateBean。这个方法里判断:
• 单例Bean • 允许循环依赖 • 正在创建中
能满足这个三个条件,则Spring会认为这个此时A是需要提前暴漏的单例Bean。因为只有提前暴漏才能解决循环依赖的问题。那么,如何提前暴漏单例Bean A呢?
如何提前暴漏Bean?
Spring的实现其实很简单,就是给A关联一个ObjectFactory对象。然后再进行Bean的初始化进程即populateBean和initializeBean,最后返回初始化之后的Bean。然后下面这一行就可以返回了。
getSingleton(String beanName, ObjectFactory<?> singletonFactory)中singletonFactory.getObject();
拿到了createBean之后的Bean A实例,相当于Bean A已经创建完成了,那么执行finally里的afterSingletonCreation方法。从singletonsCurrentlyInCreation中删除beanName(毕竟Bean已经创建结束了), 就是前边已经提到的finally块中的afterSingletonCreation(beanName);这行代码。
但是本文核心问题来了,如果Bean A依赖了Bean C,那么createBean方法执行时必然会去依赖查找Bean C,而Bean C同样执行getBean方法来实例化和初始化,在这个过程中Bean C如果依赖了Bean A,就形成了A–C—A这样的循环依赖。Bean A虽然还没初始化完成,但是在getBean查找Bean C之前却提前暴漏了自己。也就是这行代码:
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
此时怎么办呢?
//AbstractAutowireCapableBeanFactoryprotected Object doCreateBean( final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { ......... // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. //单例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(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); }catch(...){...} if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } ......... } } return exposedObject;}
重点看下提前暴漏都做了啥?
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)) { //关键代码,beanName关联singletonFactory this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }}
给Bean A关联了一个ObjectFactory,也就是getEarlyBeanReference对应的lambda函数对象。放入了singletonFactories中,当Bean C去查BeanA的时候就可以通过getEarlyBeanReference方法获取exposedObject这个早期bean对象。
/** * Obtain a reference for early access to the specified bean, * typically for the purpose of resolving a circular reference. * @param beanName the name of the bean (for error handling purposes) * @param mbd the merged bean definition for the bean * @param bean the raw bean instance * @return the object to expose as bean reference */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;}
看下Bean C怎么依赖查Bean A?
/** * Return the (raw) singleton object registered under the given name. * <p>Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); //如果C来查找A,此时会符合if条件 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { //这里C来查A一定查不到,符合下边的if条件 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { //C来查A,singletonFactories是有值的 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { //调用getEarlyBeanReference返回exposedObject singletonObject = singletonFactory.getObject(); //全局也只有此处对earlySingletonObjects进行put this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject;}
到这里,基本上已经分析完了关于单例Bean循环依赖的问题,应该还是挺清晰的
总结一下
Spring通过ObjectFactory提前暴漏一个创建中的Bean(BeanWrapper).给依赖它的Bean使用。让依赖它的Bean的初始化不再需要等待其完全初始化,避免了循环依赖的问题!
夜雨聆风
