标签:add time shared 实例 就会 protect 集合 判断 ebe
前言:在doCreateBean方法中还遗留一个问题没有分析:循环依赖。循环依赖在Spring中是非常重要的一个知识点,因此单独进行分析。
循环依赖就是循环引用,两个或两个以上的bean互相引用对方,最终形成一个闭环。如A依赖B,B依赖C,C依赖A。如下图所示:
循环依赖其实就是一个死循环的过程,在初始化A的时候发现引用了B,则就会去初始化B,然后发现B又引用C,则又去初始化C,在初始化C的时候,再次发现C引用了A,则又去初始化A,这样就处于死循环,除非有终结条件。
Spring中循环依赖的场景有两种:
构造器循环依赖
表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常。
setter循环依赖
表示通过setter注入方式构成的循环依赖,对于setter注入造成的循环依赖,Spring只解决单例模式下的循环依赖,对于其他作用域的循环依赖,则抛出BeanCurrentlyInCreationException异常。为什么Spring只解决单例模式下的循环依赖呢,这里首先了解下Spring的几个作用域。
Spring的scope作用域
从上面对Spring中scope作用域的介绍,也可大致了解为什么Spring中只解决单例模式下的循环依赖了,因为其他作用域对象的生命周期并不与Spring IOC容器一致,并且最主要的一点是Spring并不会对除了单例模式的bean做缓存,因此Spring只能解决单例模式下的循环依赖。
首先在看bean的加载的入口,在doGetBean方法中有如下代码:
首先会根据beanName从单例bean缓存中获取,如果不为空,则直接返回,前面已经分析了该方法,这里再次提出来。
1 // DefaultListableBeanFactory 2 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 3 // 从单例缓存中加载Bean 4 Object singletonObject = this.singletonObjects.get(beanName); 5 // 缓存中bean为空,且当前bean正在创建 6 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 7 // 做同步 8 synchronized (this.singletonObjects) { 9 // 从earlySingletonObjects集合中获取 10 singletonObject = this.earlySingletonObjects.get(beanName); 11 // earlySingletonObjects集合中没有,其允许提前创建 12 if (singletonObject == null && allowEarlyReference) { 13 // 从singletonFactories中获取对应的ObjectFactory 14 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 15 if (singletonFactory != null) { 16 // 获取bean 17 singletonObject = singletonFactory.getObject(); 18 // 将bean添加到earlySingletonObjects集合中 19 this.earlySingletonObjects.put(beanName, singletonObject); 20 // 从singletonFactories中移除对应的 21 this.singletonFactories.remove(beanName); 22 } 23 } 24 } 25 } 26 return singletonObject; 27 }
分析:
这里注意isSingletonCurrentlyInCreation函数,判断当前bean是否正在被创建,这里就是判断beanName是否在singletonsCurrentlyInCreation集合中,那么正在被创建的bean是合适添加进去的呢?还是在doGetBean方法中
1 // DefaultSingletonBeanRegistry 2 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 3 Assert.notNull(beanName, "Bean name must not be null"); 4 // 做同步 5 synchronized (this.singletonObjects) { 6 // 从缓存中检查一遍 7 // 因为singlton模式其实已经复用了创建的bean,所以该步骤必须检查 8 Object singletonObject = this.singletonObjects.get(beanName); 9 // 为空,开始进行加载 10 if (singletonObject == null) { 11 if (this.singletonsCurrentlyInDestruction) { 12 throw new BeanCreationNotAllowedException(beanName, 13 "Singleton bean creation not allowed while singletons of this factory are in destruction " + 14 "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 15 } 16 if (logger.isDebugEnabled()) { 17 logger.debug("Creating shared instance of singleton bean ‘" + beanName + "‘"); 18 } 19 // 加载前置处理 其实就是打一个标记 20 beforeSingletonCreation(beanName); 21 // 首先将新的newSingleton设置为false 22 boolean newSingleton = false; 23 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); 24 if (recordSuppressedExceptions) { 25 this.suppressedExceptions = new LinkedHashSet<>(); 26 } 27 try { 28 // 初始化bean 29 // 该过程其实是调用createBean()方法 这里是一个回调方法 30 singletonObject = singletonFactory.getObject(); 31 newSingleton = true; 32 } catch (IllegalStateException ex) { 33 // Has the singleton object implicitly appeared in the meantime -> 34 // if yes, proceed with it since the exception indicates that state. 35 singletonObject = this.singletonObjects.get(beanName); 36 if (singletonObject == null) { 37 throw ex; 38 } 39 } catch (BeanCreationException ex) { 40 if (recordSuppressedExceptions) { 41 for (Exception suppressedException : this.suppressedExceptions) { 42 ex.addRelatedCause(suppressedException); 43 } 44 } 45 throw ex; 46 } finally { 47 if (recordSuppressedExceptions) { 48 this.suppressedExceptions = null; 49 } 50 // 一堆异常处理后,进行后置处理 移除标志 51 afterSingletonCreation(beanName); 52 } 53 // 新的bean 加入缓存中 54 if (newSingleton) { 55 addSingleton(beanName, singletonObject); 56 } 57 } 58 return singletonObject; 59 }
分析:
注意第20行代码beforeSingletonCreation函数。
1 // DefaultSingletonBeanRegistry 2 protected void beforeSingletonCreation(String beanName) { 3 // 这里会添加到正在创建bean的集合中 4 // 注意第一个条件,如果存在,则为false,直接短路 5 // 只有当第一个条件不存在[false]时,才会去进行添加操作 6 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { 7 throw new BeanCurrentlyInCreationException(beanName); 8 } 9 }
分析:
这里就会将正在创建的beanName添加到singletonsCurrentlyInCreation,如果出现构造函数的循环依赖bean注入,则会在此处抛出BeanCurrentlyCreationException异常,具体可以跟着代码调试一把,就可以更清楚的知晓流程。
接下来继续回到单例模式的循环依赖中:
在加载bean时,首先从单例缓存中获取bean对象。
注意这里涉及到三个集合:
1 /** 2 * Cache of singleton objects: bean name to bean instance. 3 * 存放的是单例 bean 的映射。 4 * <p> 5 * 对应关系为 bean name --> bean instance 6 */ 7 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 8 9 /** 10 * Cache of singleton factories: bean name to ObjectFactory.<br/> 11 * 存放的是 ObjectFactory,可以理解为创建单例 bean 的 factory 。 12 * <p> 13 * 对应关系是 bean name --> ObjectFactory 14 */ 15 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 16 17 /** 18 * Cache of early singleton objects: bean name to bean instance.<br/> 19 * 存放的是早期的 bean,对应关系也是 bean name --> bean instance。 20 * <p> 21 * 它与 {@link #singletonFactories} 区别在于 earlySingletonObjects 中存放的 bean 不一定是完整。 22 * <p> 23 * 从 {@link #getSingleton(String)} 方法中,我们可以了解,bean 在创建过程中就已经加入到 earlySingletonObjects 中了。 24 * 所以当在 bean 的创建过程中,就可以通过 getBean() 方法获取。 25 * <p> 26 * 这个 Map 也是【循环依赖】的关键所在。 27 */ 28 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
这三个缓存集合就是解决Spring中循环依赖的所在,具体流程:
如果从单例缓存中得到bean对象,则会调用getObjectForBeanInstance方法进一步处理,因为从缓存中得到的bean是最原始的bean,并不一定是最终所需要的bean对象。
上面分析了从缓存中获取bean对象,但是缓存中的值是从什么地方添加进来的呢?如果你调试过源码会发现这样一段代码:
1 // AbstractAutowireCapableBeanFactory 2 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 3 isSingletonCurrentlyInCreation(beanName));// 当前单例bean是否正在被创建 4 if (earlySingletonExposure) { 5 if (logger.isDebugEnabled()) { 6 logger.debug("Eagerly caching bean ‘" + beanName + 7 "‘ to allow for resolving potential circular references"); 8 } 9 // 提前将创建的bean实例加入到singletonFactories中 10 // 为了后期避免循环依赖 11 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 12 }
分析:
当一个bean满足三个条件,则会被加入到缓存中。三个条件如下:
DefaultSingletonBeanRegistry#addSingletonFactroy
1 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { 2 Assert.notNull(singletonFactory, "Singleton factory must not be null"); 3 synchronized (this.singletonObjects) { 4 if (!this.singletonObjects.containsKey(beanName)) { 5 this.singletonFactories.put(beanName, singletonFactory); 6 this.earlySingletonObjects.remove(beanName); 7 this.registeredSingletons.add(beanName); 8 } 9 } 10 }
分析:
上面介绍的了三级缓存[singletonFactories]与二级缓存[earlySingletonObjects]的出处,接下来看一级缓存的出处:
在DefaultSingletonBeanRegistry#getSingleton函数中:
1 public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { 2 Assert.notNull(beanName, "Bean name must not be null"); 3 // 做同步 4 synchronized (this.singletonObjects) { 5 // 从缓存中检查一遍 6 // 因为singlton模式其实已经复用了创建的bean,所以该步骤必须检查 7 Object singletonObject = this.singletonObjects.get(beanName); 8 // 为空,开始进行加载 9 if (singletonObject == null) { 10 if (this.singletonsCurrentlyInDestruction) { 11 throw new BeanCreationNotAllowedException(beanName, 12 "Singleton bean creation not allowed while singletons of this factory are in destruction " + 13 "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); 14 } 15 if (logger.isDebugEnabled()) { 16 logger.debug("Creating shared instance of singleton bean ‘" + beanName + "‘"); 17 } 18 // 加载前置处理 其实就是打一个标记 19 beforeSingletonCreation(beanName); 20 // 首先将新的newSingleton设置为false 21 boolean newSingleton = false; 22 boolean recordSuppressedExceptions = (this.suppressedExceptions == null); 23 if (recordSuppressedExceptions) { 24 this.suppressedExceptions = new LinkedHashSet<>(); 25 } 26 try { 27 // 初始化bean 28 // 该过程其实是调用createBean()方法 这里是一个回调方法 29 singletonObject = singletonFactory.getObject(); 30 newSingleton = true; 31 } catch (IllegalStateException ex) { 32 // Has the singleton object implicitly appeared in the meantime -> 33 // if yes, proceed with it since the exception indicates that state. 34 singletonObject = this.singletonObjects.get(beanName); 35 if (singletonObject == null) { 36 throw ex; 37 } 38 } catch (BeanCreationException ex) { 39 if (recordSuppressedExceptions) { 40 for (Exception suppressedException : this.suppressedExceptions) { 41 ex.addRelatedCause(suppressedException); 42 } 43 } 44 throw ex; 45 } finally { 46 if (recordSuppressedExceptions) { 47 this.suppressedExceptions = null; 48 } 49 // 一堆异常处理后,进行后置处理 移除标志 50 afterSingletonCreation(beanName); 51 } 52 // 新的bean 加入缓存中 53 if (newSingleton) { 54 addSingleton(beanName, singletonObject); 55 } 56 } 57 return singletonObject; 58 } 59 }
分析:
这里关注第54行处:addSingleton函数。
1 // DefaultSingletonBeanRegistry 2 protected void addSingleton(String beanName, Object singletonObject) { 3 synchronized (this.singletonObjects) { 4 this.singletonObjects.put(beanName, singletonObject); 5 this.singletonFactories.remove(beanName); 6 this.earlySingletonObjects.remove(beanName); 7 this.registeredSingletons.add(beanName); 8 } 9 }
分析:
这里就是将bean加入一级缓存中[singletonObjects],同时remove二级缓存和三级缓存中值,因为bean已经被创建成功了,二级缓存与三级缓存也就不需要了。
从上面分析过程可以知道为什么Spring只解决单例模式下的循环依赖了吧?
单例模式下循环依赖解决流程:
如果你看过《Spring源码深度解析》这本书,还能发现如下流程图:
注:看图说话,笔者最为喜欢!其实去亲身调试一下循环依赖的代码,可能会有更加深刻的认识。
by Shawn Chen,2019.04.29,下午。
标签:add time shared 实例 就会 protect 集合 判断 ebe
原文地址:https://www.cnblogs.com/developer_chan/p/10783620.html