主流手机芯片性能排行
自我解惑: 问:还是不太懂,为什么这么设计呢,即使有代理,在二级缓存代理也可以吧 | 为什么要使用三级缓存呢? 我们再来看下相关代码,假设我们现在是二级缓存架构,创建 A 的时候,我们不知道有没有循环依赖,所以放入二级缓存提前暴露,接着创建 B,也是放入二级缓存,这时候发现又循环依赖了 A,就去二级缓存找,是有,但是如果此时还有 AOP 代理呢,我们要的是代理对象可不是原始对象,这怎么办,只能改逻辑,在第一步的时候,不管3721,所有 Bean 统统去完成 AOP 代理,如果是这样的话,就不需要三级缓存了,但是这样不仅没有必要,而且违背了 Spring 在结合 AOP 跟 Bean 的生命周期的设计。
所以 Spring “多此一举”的将实例先封装到 ObjectFactory 中(三级缓存),主要关键点在 getObject() 方法并非直接返回实例,而是对实例又使用 SmartInstantiationAwareBeanPostProcessor 的 getEarlyBeanReference 方法对 bean 进行处理,也就是说,当 Spring 中存在该后置处理器,所有的单例 bean 在实例化后都会被进行提前曝光到三级缓存中,但是并不是所有的 bean 都存在循环依赖,也就是三级缓存到二级缓存的步骤不一定都会被执行,有可能曝光后直接创建完成,没被提前引用过,就直接被加入到一级缓存中。因此可以确保只有提前曝光且被引用的 bean 才会进行该后置处理。 流程其实上边都已经说过了,结合着上图我们再看下具体细节,用大白话再捋一捋:
这就是单例模式下 Spring 解决循环依赖的流程了。 但是这个地方,不管是谁看源码都会有个小疑惑,为什么需要三级缓存呢,我赶脚二级他也够了呀 革命尚未成功,同志仍需努力
跟源码的时候,发现在创建 beanB 需要引用 beanA 这个“半成品”的时候,就会触发"前期引用",即如下代码: 2.getObject() 匿名内部类的实现真正调用的又是 createBean(beanName, mbd, args) 3.往里走,主要的实现逻辑在 doCreateBean方法,先通过 createBeanInstance 创建一个原始 bean 对象 4.接着 addSingletonFactory 添加 bean 工厂对象到 singletonFactories 缓存(三级缓存) 5.通过 populateBean 方法向原始 bean 对象中填充属性,并解析依赖,假设这时候创建 A 之后填充属性时发现依赖 B,然后创建依赖对象 B 的时候又发现依赖 A,还是同样的流程,又去 getBean(A),这个时候三级缓存已经有了 beanA 的“半成品”,这时就可以把 A 对象的原始引用注入 B 对象(并将其移动到二级缓存)来解决循环依赖问题。这时候 getObject() 方法就算执行结束了,返回完全实例化的 bean 6.最后调用 addSingleton 把完全实例化好的 bean 对象放入 singletonObjects 缓存(一级缓存)中,打完收工 Spring 解决循环依赖
建议搭配着“源码”看下边的逻辑图,更好下饭 (编辑:长春站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |