Spring 系列目录(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
Spring 循环引用相关文章:java
Spring 对单例 bean 的管理都是在 DefaultSingletonBeanRegistry 中完成的,这里会涉及到其内部所使用的几个内部属性:spring
// 1.1 保存最终建立成功的单例 beanName -> beanInstance private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 1.2 中间变量,beanName -> Objectfactory private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 1.3 中间变量,bean 还在建立的时候就能够获取,用于检测循环引用 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
这里涉及用于存储 bean 的不一样的 Map,可能让人感到崩溃,简单解释以下:缓存
singletonObjects
:用于保存 beanName 和建立 bean 实例之间的关系。beanName -> beanInstancesingletonFactories
:用于保存 beanName 和对象工厂的引用关系,一旦最终对象被建立(经过 objectFactory.getObject()),此引用信息将删除。beanName -> ObjectfactoryearlySingletonObjects
:用于保存 beanName 和建立的原始 bean 的引用关系,注意这里是原始 bean,即便用工厂方法或构造方法建立出来的对象,一旦对象最终建立好,此引用信息将删除。 与 singletonObjects 的不一样之处在于,此时 bean 还在建立过程当中,并且以后还能够进行加强,也就是代理后这两个 bean 就不是同一个了。能够经过 getBean 方法获取到了,其目的是用来检测循环引用。从上面的解释,能够看出,这 singletonFactories 和 earlySingletonObjects 都是一个临时的辅助状态。在全部的对象建立完毕以后,此两个对象的 size 都为 0。那么再来看下这两个对象如何进行协做:app
(1) 方法1:建立单例对象ide
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 1. 将这个 bean 添加到 singletonsCurrentlyInCreation 集合中,这样就能够判断 bean 是否存在建立 beforeSingletonCreation(beanName); // 2. 初始化 bean,委托给 ObjectFactory 完成 singletonObject = singletonFactory.getObject(); // 3. 从 singletonsCurrentlyInCreation 移除该 bean afterSingletonCreation(beanName); // 4. 建立完成进行注册,这样下次就能够从缓存中直接获取这个对象了 addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); } }
(2) 方法2:单例对象建立完成进行注册源码分析
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); } }
(3) 方法3:将实例化后的对象暴露到容器中this
Spring 在 bean 实例化后就会调用 addSingletonFactory 将这个对象提早暴露到容器中,这们就能够经过 getBean(A) 获得这个对象,即便这个对象仍正在建立。用于解决循环依赖。代理
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); } } }
(4) 方法4:从缓存中获取 beancode
这个方法也是专门用于解决循环依赖的问题,当不存在循环依赖时 earlySingletonObjects 老是 null。
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; }
咱们从 BeanFactory#getBean(beanName) 调用提及,看一下这几个方法的调用顺序:
这个方法先从缓存中获取 bean,没有再建立 bean,所以会调用方法 4 和方法 1,咱们看一下调用过程。
(1) getSingleton(beanName, true)
doGetBean 首先从缓存中获取数据,Object sharedInstance = getSingleton(beanName)
,这个方法最终会调用 getSingleton(beanName, true)
。
(2) getSingleton(beanName, singletonFactory)
若是缓存中没有 bean,则会调用 addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
来建立一个新 bean,代码以下:
if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
一旦调用 getSingleton(beanName, singletonFactory) 方法,这个方法建立开始时就会标记这个 bean 为正在建立,建立结束后移除对应的标记。直接建立 bean 的过程其实是委托给了 createBean 方法。继续跟踪这个方法。
doCreateBean 方法中完成了单例的 bean 有如下几个主要的步骤:
createBeanInstance
实例化 bean 对象,通常是经过反射调用默认的构造器。populateBean
bean 属性注入,在这个步骤会从 Spring 容器中查找对应属性字段的值,解决循环依赖问题。initializeBean
调用的 bean 定义的初始化方法。(3) addSingletonFactory(beanName, singletonFactory)
在 createBeanInstance 后 populateBean 前 Spring 会将这个实例化的 bean 提早暴露到容器中,这样 populateBean 属性注入时就能够经过 getBean(A) 查找到。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
(4) getSingleton(beanName, false)
在 bean 初始化完成还后还须要进行依赖的检查,这时由于提早暴露的这个 bean(即便用工厂方法或构造方法建立出来的对象) initializeBean 还能够进行加强,这样这两个 bean 就不是同一个了。Spring 默认是不容许这种状况发生的。
if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } }
(5) addSingleton(beanName, singletonObject)
在 bean 建立结束后还有一步是在 getSingleton(beanName, singletonFactory) 中完成的,调用 addSingleton(beanName, singletonObject),即注册最终的 bean,同时清空中间的辅助状态。
这样单例 bean 的建立过程就完成了,下面就须要分析循环引用下 singletonFactories、earlySingletonObjects 这两个集合的状态。
在正常的状况下,调用顺序以下:如下有无,表示是否持有对指定 Bean 的引用
过程 | 方法 | singletonFactories | earlySingletonObjects | singletonObjects |
---|---|---|---|---|
缓存中获取 | getSingleton(beanName, true) | 无 | 无 | 无 |
建立 bean | getSingleton(beanName, singletonFactory) | 无 | 无 | 无 |
提早暴露到容器中 | addSingletonFactory(beanName, singletonFactory) | 有 | 无 | 无 |
依赖检查 | getSingleton(beanName, false) | 有 | 无 | 无 |
注册 | addSingleton(beanName, singletonObject) | 无 | 无 | 有 |
能够看到正常状况下,单例 bean 暴露的对象只会出如今 singletonFactories 集合中,不可能出如今 earlySingletonObjects 集合中,除非在建立 bean 的过程当中又调用了 getSingleton(beanName, true) 方法,也就是此时出现了循环引用。
可是出现循环引用以后呢,就会出现这种状况:
过程 | 方法 | singletonFactories | earlySingletonObjects | singletonObjects |
---|---|---|---|---|
缓存中获取 A | getSingleton(A, true) | A无B无 | A无B无 | A无B无 |
建立 A | getSingleton(A, singletonFactory) | A无B无 | A无B无 | A无B无 |
暴露 A 到容器中 | addSingletonFactory(A, singletonFactory) | A有B无 | A无B无 | A无B无 |
populateBean(A, mbd, instanceWrapper) A 注入 B 时又依赖了 A,此时由 B 准备解析 A…… | ||||
缓存中获取 A | getSingleton(A, true) | A无B有 | A有B无 | A无B无 |
注册 B | addSingleton(B, singletonObject) | A无B无 | A有B无 | A无B有 |
populateBean(A, mbd, instanceWrapper) 完成属性注入 | ||||
A- = initializeBean(beanName, exposedObject, mbd) 在 initializeBean 以后 A 变为 A- | ||||
依赖检查 | getSingleton(beanName, false) | A无B无 | A有B无 | A无B有 |
注册 A | getSingleton(beanName, false) | A无B无 | A无B无 | A有B有 |
在上面这个过程当中,在对 A 进行验证时,就会从 earlySingletonObjects 中取得一个 A,可是这个 A 和后面的 A- 可能不是同一个对象,这是由于有了 beanPostProcessor 存在,它能够改变 bean 的最终值,好比对原始 bean 进行封装,代理等。在这个过程当中,出现了 3 个对象 A, A-, B,而 B 中所持有的 A 对象为原始的 A。若是这里的 A 和 A- 不是同一个对象,即产生了 beanA 有了 beanB 的引用,但 beanB 并无 beanA 的引用,而是另外一个 beanA 的引用。
天天用心记录一点点。内容也许不重要,但习惯很重要!