3.4 spring5源码系列–循环依赖的设计思想
前面已经写了关于三篇循环依赖的文章, 这是一个总结篇
第一篇: 3.1 spring5源码系列–循环依赖 之 手写代码模拟spring循环依赖
第三篇: 3.3 Spring5源码—循环依赖过程中spring读取不完整bean的最终
现在总结循环依赖的思想
思想才是我们可以在工作中借鉴使用的
1. 循环依赖的三级缓存设计
2. 接口函数
一. 循环依赖的三级缓存设计
再循环依赖的过程中设计了三级缓存, 他们的作用分别是
1. 一级缓存: 用来存放完整的bean
2. 二级缓存: 用来存放早期的,纯净的bean
3. 三级缓存: 用来存放接口函数.
/** Cache of singleton objects: bean name to bean instance. */ /** * 一级缓存 这个就是我们大名鼎鼎的缓存池, 用于保存我们所有的实例bean */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ /** * 三级缓存 该map用户缓存key为beanName, value为objectFactory(包装为早期对象) */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ /** * 二级缓存, 用户缓存我们的key为beanName, value是我们的早期对象(此时对象属性还没有...) */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
细细想来, 这三个缓存都非常有存在的必要.
1.1 如果去掉二级缓存, 只有一个一级缓存可不可以?
我们知道, 最开始有的是二级缓存. 因为是在createBean的三个步骤中,第一个步骤实例化bean的时候加入到二级缓存的. 这个时候为什么一定要加入二级缓存呢, 如果不加入会怎么样呢?
也就是去掉二级缓存可不可以. 当然是不可以的. 去掉二级缓存, 那就是最后整个bean经历三个过程都被创建成功以后, 将一个成熟的bean放入到一级缓存中. 这中间有什么问题呢?
问题在于多线程. 整个bean创建的过程那么长, 多线程进来. 其实bean已经在创建中了, 可是因为还没有放入到一级缓存, 所以会认为没有创建. 导致重复创建bean.
1.2 三级缓存到底什么用?
三级缓存里存放的是一个接口函数. 这个接口函数什么用呢? 就相当于js中的回调函数. 我在前面定义好, 但是不执行. 直到满足条件了, 才执行. 这个方法, 可以大范围应用到实践工作中.
比如: 调用动态代理创建bean. 刚开始实例化完成以后, 我就赋予你这个能力, 你可以调用动态代理. 但是, 到后面, 你是否真的能够运用这个能力呢? 不一定, 只有满足条件, 才会运用这个能力.
二. 定义接口函数, 也叫钩子函数
在循环依赖源码中, 两次使用到接口函数的方式.
第一个是创建bean的时候. 第二个是三级缓存
下面来看看源码,
第一次: 创建bean的时候, 定义了一个钩子函数createBean()
sharedInstance = getSingleton(beanName, () -> { try { // 这里定义了一个钩子函数. 此时只是定义, 并不执行. 在真正需要创建bean的地方才会执行 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; } });
实际上调用的时机是: 在getSingleton方法里面. 回调接口函数.
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { // 第一步: 从一级缓存中获取单例对象 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 第二步: 将bean添加到singletonsCurrentlyInCreation中, 表示bean正在创建 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 第三步: 这里调用getObject()钩子方法, 就会回调匿名函数, 调用singletonFactory的createBean() singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
第二次调用: 是在三级缓存定义的时候
调用addSingletonFactory(…)定义了一个钩子函数. 这里仅仅是定义, 并不执行
// 把我们的早期对象包装成一个singletonFactory对象, 该对象提供了getObject()方法, 把静态的bean放到三级缓存中去了. addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
然后进入到addSingletonFactory内部, 只是把singletonFactory放入到了三级缓存中, 这里只是定义, 也并没有执行
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); // 添加到已经注册的singleton实例. this.registeredSingletons.add(beanName); } } }
什么时候执行的呢? 再从缓存中获取对象的时候.
@Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 从一级缓存中获取bean实例对象 Object singletonObject = this.singletonObjects.get(beanName); /** * 如果在第一级的缓存中没有获取到对象, 并且singletonsCurrentlyIncreation为true,也就是这个类正在创建. * 标明当前是一个循环依赖. * * 这里有处理循环依赖的问题.-- 我们使用三级缓存解决循环依赖 */ if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { /** * 从二级缓存中拿bean, 二级缓存中的对象是一个早期对象 * 什么是早期对象?就是bean刚刚调用了构造方法, 还没有给bean的属性进行赋值, 和初始化, 这就是早期对象 */ singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { /** * 从三级缓存拿bean, singletonFactories是用来解决循环依赖的关键所在. * 在ios后期的过程中, 当bean调用了构造方法的时候, 把早期对象包装成一个ObjectFactory对象,暴露在三级缓存中 */ ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { /** * 在这里通过暴露的ObjectFactory包装对象. 通过调用他的getObject()方法来获取对象 * 在这个环节中会调用getEarlyBeanReference()来进行后置处理 */ singletonObject = singletonFactory.getObject(); // 把早期对象放置在二级缓存中 this.earlySingletonObjects.put(beanName, singletonObject); // 删除三级缓存 this.singletonFactories.remove(beanName); } } } } return singletonObject; }
在这里调用三级缓存, singletonObject = singletonFactory.getObject(); 回调钩子函数.


