wordpress 创建网站,怎么设计一个app,黄骅港海关,郑州正规的网站设计解决方案
使用提前暴露机制三级缓存进行解决
singletonObjects一级缓存#xff0c;存放完整的 Bean。earlySingletonObjects二级缓存#xff0c;存放提前暴露的Bean#xff0c;Bean 是不完整的#xff0c;未完成属性注入和执行 init 方法。singletonFactories三级缓存(用…解决方案
使用提前暴露机制三级缓存进行解决
singletonObjects一级缓存存放完整的 Bean。earlySingletonObjects二级缓存存放提前暴露的BeanBean 是不完整的未完成属性注入和执行 init 方法。singletonFactories三级缓存(用Map类型的该参数来存放beanName和beanFactory之间的关系)存放的是 Bean 工厂通过BeanFactory的getObject拿到实例然后重新将值赋给二级缓存。
这里只用 AB 形成的循环依赖来举例
实例化 A此时 A 还未完成属性填充和初始化方法PostConstruct的执行A 只是一个半成品。为 A 创建一个 Bean 工厂并放入到 singletonFactories 中。发现 A 需要注入 B 对象但是一级、二级、三级缓存均为发现对象 B。实例化 B此时 B 还未完成属性填充和初始化方法PostConstruct的执行B 只是一个半成品。为 B 创建一个 Bean 工厂并放入到 singletonFactories 中。发现 B 需要注入 A 对象此时在一级、二级未发现对象 A但是在三级缓存中发现了对象 A从三级缓存中得到对象 A通过工厂生成半成品Bean提前暴露并将对象 A 放入二级缓存中同时删除三级缓存中的对象 A。注意此时的 A 还是一个半成品并没有完成属性填充和执行初始化方法将对象 A 注入到对象 B 中。对象 B 完成属性填充执行初始化方法并放入到一级缓存中同时删除二级缓存中的对象 B。此时对象 B 已经是一个成品对象 A 得到对象 B将对象 B 注入到对象 A 中。对象 A 得到的是一个完整的对象 B对象 A 完成属性填充执行初始化方法并放入到一级缓存中同时删除二级缓存中的对象 A。
思考1
只使用一级缓存是否可以解决循环依赖
答案是否定的Bean的创建过程 createBeanInstance -- populateBean -- initializeBean可以推断出是在initializeBean才插入一级缓存的。
由上面推断 initializeBean 的时候记录缓存在循环依赖的情况需要在 populateBean(第二阶段) 的时候再去注入循环依赖的 bean此时缓存中是没有循环依赖的 bean 的就会导致 bean 重新创建实例。 如果被循环依赖的 bean 是一个 AOP 增强的代理 bean 的话bean 的原始引用和最终产生的 AOP 增强 bean 的引用是不一样的一级缓存就搞不定了。 当 aop 代理 bean 被循环依赖时getBean() 操作从缓存中获取到的是一级缓存中存放的原始对象而不是代理对象。 假如createBeanInstance 之后就生成代理对象提前放入一级缓存呢
答案是否定的如果在 populateBean 之前生成的是一个代理对象的话会导致一个问题 jdk proxy 产生的代理对象是实现的目标类的接口jdk proxy 的代理类通过 BeanWrapper 去利用反射设置值时会因为找不到相应的属性或者方法而报错。
思考2
不需要第三级缓存是否可以解决循环依赖
答案是可以的二级缓存来解决循环依赖的话那么每个 bean 的创建流程中都需要插入一个流程——创建 bean 的早期引用提前暴露放入二级缓存。其实在真实的开发中绝大部分的情况下都不涉及到循环依赖而且 createBeanInstance -- populateBean -- initializeBean 这个流程也更加符合常理。所以猜想 Spring 不用二级缓存来解决循环依赖问题是为了保证处理时清晰明了bean 的创建就是三个阶段: createBeanInstance -- populateBean -- initializeBean 只有碰到 AOP 代理 bean 被循环依赖时的场景才去特殊处理提前生成 AOP 代理 bean
思考3
去掉二级缓存是否可以解决循环依赖
答案是否定的在AOP的前提下这么一种场景B 和 C 都依赖了 A。singletonFactory.getObject() 获取的是代理对象。多次调用该方法返回的代理对象是不同的。
思考4
Spring 一开始提前暴露的并不是实例化的 Bean而是将 Bean 包装起来的 ObjectFactory。为什么要这么做呢
这实际上涉及到 AOP如果创建的 Bean 是有代理的那么注入的就应该是代理 Bean而不是原始的 Bean。但是 Spring 一开始并不知道 Bean 是否会有循环依赖通常情况下没有循环依赖的情况下Spring 都会在完成填充属性并且执行完初始化方法之后再为其创建代理。但是如果出现了循环依赖的话Spring 就不得不为其提前创建代理对象否则注入的就是一个原始对象而不是代理对象。Spring 的做法就是在 ObjectFactory 中去提前创建代理对象。 Spring 需要三级缓存的目的是为了在没有循环依赖的情况下延迟代理对象的创建