前面已经写了关于三篇循环依赖的文章,这是一个总结篇
第一篇: 3.1 spring5源码系列--循环依赖 之 手写代码模拟spring循环依赖
第二篇: 3.2spring源码系列----循环依赖源码分析
第三篇: 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(包装为早期对象) singletonFactories = new HashMap<>(16* Cache of early singleton objects: bean name to bean instance. * * 二级缓存,用户缓存我们的key为beanName,value是我们的早期对象(此时对象属性还没有...) earlySingletonObjects = 16);
细细想来,这三个缓存都非常有存在的必要.
1.1 引入一级缓存
刚开始,只有一级缓存,在整个bean创建完成以后,将其完整的bean放入到一级缓存中. 这样有什么问题?
1. bean创建一共有三大步骤,(实例化,属性赋值,初始化) 等到整个过程都创建完,在存入一级缓存,多线程怎么办? 第一个线程创建bean的过程中,又来了一个线程,他发现一级缓存这时候还没有,就回去再次创建. 那不就重复了么? ioc要求,bean是单例的.
2. 加锁,加锁能否解决这个问题? 能,但是效率超级低. 对一级缓存加锁,那么所有的对象创建过程中都要等待. 哪怕人家已经创建成功过. 效率太低,不能接受
3. 于是就引入了二级缓存.
1.2 引入二级缓存
二级缓存的引入,可以解决一级缓存创建bean链路过长的问题,他在bean一旦被创建,立刻就放入到二级缓存. 整个bean创建完成以后,在放入到一级缓存,删除二级缓存. 这样做可以解决多线程创建bean的问题. 缩短了整个链路. 同时,每次从缓存中先获取bean,如果一级缓存中已经有了,那么直接返回. 不用在执行后面的创建代码
那么,二级缓存有什么问题呢?
这就还需要知道一个问题,那就是动态代理创建bean. 什么时候,去使用动态代理创建bean? 通常我们说在初始化之后,调用bean的后置处理器创建bean. 这只是大多数bean创建动态代理的时候. 那如果有循环依赖呢? 有循环依赖,还在初始化之后创建就晚了. 这是需要在实例化之后创建. 这样,动态代理的代码就和创建bean耦合在一块了. 违背单一性原则.
于是,引入了三级缓存
1.3 引入三级缓存
三级缓存的引入是为了解决耦合问题. 让每一个方法只做一件事. 巧妙的使用了接口函数.
这个接口函数什么用呢? 就相当于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 (.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName,1)">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 == ); (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } { // 第三步: 这里调用getObject()钩子方法,就会回调匿名函数,调用singletonFactory的createBean() singletonObject = singletonFactory.getObject(); newSingleton = true; } (IllegalStateException ex) { Has the singleton object implicitly appeared in the meantime -> if yes,proceed with it since the exception indicates that state. singletonObject = (beanName); ) { throw ex; } } (BeanCreationException ex) { (recordSuppressedExceptions) { for (Exception suppressedException : .suppressedExceptions) { ex.addRelatedCause(suppressedException); } } ex; } finally { ; } afterSingletonCreation(beanName); } (newSingleton) { addSingleton(beanName,singletonObject); } } singletonObject; } }
第二次调用: 是在三级缓存定义的时候
调用addSingletonFactory(...)定义了一个钩子函数. 这里仅仅是定义,并不执行
把我们的早期对象包装成一个singletonFactory对象,该对象提供了getObject()方法,把静态的bean放到三级缓存中去了.
addSingletonFactory(beanName,() -> getEarlyBeanReference(beanName,bean));
然后进入到addSingletonFactory内部,只是把singletonFactory放入到了三级缓存中,这里只是定义,也并没有执行
protected void addSingletonFactory(String beanName,ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory,1)">Singleton factory must not be nullif (!.singletonObjects.containsKey(beanName)) { 加入到三级缓存中,暴露早期对象用于解决循环依赖. this.singletonFactories.put(beanName,singletonFactory); 从二级缓存中删除 .earlySingletonObjects.remove(beanName); 添加到已经注册的singleton实例. .registeredSingletons.add(beanName); } } }
什么时候执行的呢? 再从缓存中获取对象的时候.
@Nullable protected Object 从一级缓存中获取bean实例对象 Object singletonObject = (beanName); * * 如果在第一级的缓存中没有获取到对象,并且singletonsCurrentlyIncreation为true,也就是这个类正在创建. * 标明当前是一个循环依赖. * * 这里有处理循环依赖的问题.-- 我们使用三级缓存解决循环依赖 */ null && isSingletonCurrentlyInCreation(beanName)) { synchronized (.singletonObjects) { * * 从二级缓存中拿bean,二级缓存中的对象是一个早期对象 * 什么是早期对象?就是bean刚刚调用了构造方法,还没有给bean的属性进行赋值,和初始化,这就是早期对象 */ singletonObject = this.earlySingletonObjects.(beanName); allowEarlyReference) { * * 从三级缓存拿bean,singletonFactories是用来解决循环依赖的关键所在. * 在ios后期的过程中,当bean调用了构造方法的时候,把早期对象包装成一个ObjectFactory对象,暴露在三级缓存中 */ ObjectFactory<?> singletonFactory = this.singletonFactories.(beanName); if (singletonFactory != ) { /** * 在这里通过暴露的ObjectFactory包装对象. 通过调用他的getObject()方法来获取对象 * 在这个环节中会调用getEarlyBeanReference()来进行后置处理 */ singletonObject = singletonFactory.getObject(); 把早期对象放置在二级缓存中 .earlySingletonObjects.put(beanName,singletonObject); 删除三级缓存 .singletonFactories.remove(beanName); } } } } singletonObject; }
在这里调用三级缓存, singletonObject = singletonFactory.getObject(); 回调钩子函数.