当前位置: 首页 > wzjs >正文

向自己做网站wordpress技术博客模板下载

向自己做网站,wordpress技术博客模板下载,福泉市建设局网站,兴化 网站开发目录 三级缓存核心原理 循环依赖的解决过程 1. Bean A创建过程中提前曝光工厂 2. Bean B创建时发现依赖A,从缓存获取 3. Bean A继续完成初始化 三级缓存的作用总结 二级缓存为何不够解决缓存依赖? 三级缓存如何解决? 为什么不直接在…

目录

三级缓存核心原理

循环依赖的解决过程

1. Bean A创建过程中提前曝光工厂

2. Bean B创建时发现依赖A,从缓存获取

3. Bean A继续完成初始化

三级缓存的作用总结

二级缓存为何不够解决缓存依赖?

三级缓存如何解决?

为什么不直接在实例化后创建代理?

总结


Spring通过三级缓存机制解决循环依赖问题,这与populateBean()方法密切相关。下面我用简化代码解释这个机制:

三级缓存核心原理

Spring在DefaultSingletonBeanRegistry中维护了三个重要的缓存:

// 一级缓存:存储完全初始化的单例bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:存储早期曝光的单例bean(未完全初始化)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三级缓存:存储单例工厂对象,用于创建早期曝光的bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

循环依赖的解决过程

当发生循环依赖时,Spring通过以下步骤解决:

1. Bean A创建过程中提前曝光工厂
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1. 实例化Bean(调用构造函数)BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);// 2. 提前曝光一个ObjectFactory,用于解决循环依赖boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences);if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 填充属性(可能触发对Bean B的依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化Bean(调用init方法和AOP代理)exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}// 将工厂添加到三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}
}
2. Bean B创建时发现依赖A,从缓存获取

populateBean()处理B的依赖时:

protected Object resolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {// 查找依赖的bean(假设这里是A)String dependencyName = descriptor.getDependencyName();// 从三级缓存中获取beanObject bean = getSingleton(dependencyName, false);return bean;
}// 从三级缓存中获取bean的核心方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 先从一级缓存获取Object singletonObject = this.singletonObjects.get(beanName);// 2. 如果一级缓存没有且bean正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 3. 从二级缓存获取singletonObject = this.earlySingletonObjects.get(beanName);// 4. 二级缓存没有且允许早期引用if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 5. 从三级缓存获取工厂ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 6. 通过工厂创建早期bean实例singletonObject = singletonFactory.getObject();// 7. 放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);// 8. 从三级缓存移除this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
3. Bean A继续完成初始化

当B完成创建后,A继续完成自己的初始化:

// 完成Bean A的初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);// 将完全初始化的bean放入一级缓存
addSingleton(beanName, exposedObject);protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);}
}

三级缓存的作用总结

  1. 一级缓存(singletonObjects):存储完全初始化的单例bean,可直接使用
  2. 二级缓存(earlySingletonObjects):存储早期曝光的bean(未完成初始化),用于解决循环依赖
  3. 三级缓存(singletonFactories):存储工厂对象,允许在需要时创建早期bean,并支持AOP代理

通过这种机制,Spring允许在bean尚未完全初始化时就将其引用暴露给依赖它的其他bean,从而解决循环依赖问题。注意:只有单例作用域的bean支持循环依赖,原型模式不支持。你的问题非常关键!实际上,二级缓存理论上可以解决循环依赖,但Spring依然使用三级缓存,主要出于AOP代理的考虑。我来详细解释:

二级缓存为何不够解决缓存依赖?

假设只有两级缓存:

  1. singletonObjects(完全初始化的bean)
  2. earlySingletonObjects(早期曝光的bean)

当出现循环依赖时,我们可以在实例化后直接将bean放入earlySingletonObjects。但这样会有一个问题:如果bean需要AOP代理,早期曝光的将是原始对象,而不是代理对象

举个例子:

// Bean A依赖B,Bean B依赖A
class A {@Autowired private B b;@Transactional public void doSomething() {} // 需要AOP代理
}class B {@Autowired private A a;
}

当A和B循环依赖时:

  1. A实例化后放入二级缓存(此时是原始对象)
  2. B创建时从二级缓存获取A的原始对象
  3. B完成创建,注入A的原始对象
  4. A继续初始化,创建代理对象

最终结果:B持有的是A的原始对象,而不是代理对象,导致AOP失效!

三级缓存如何解决?

Spring通过三级缓存引入了ObjectFactory,将AOP代理的创建延迟到真正需要早期引用时:

// 三级缓存:存储工厂对象,用于创建可能需要代理的早期bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 添加工厂到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 获取早期引用的方法(可能创建代理)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会创建代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

当B需要A的早期引用时:

  1. 从三级缓存获取ObjectFactory
  2. 通过工厂调用getEarlyBeanReference(),此时才决定是否创建代理
  3. 将结果(可能是代理对象)放入二级缓存

这样一来,B持有的就是A的代理对象,保证了AOP的正确性。

为什么不直接在实例化后创建代理?

你可能会问:为什么不直接在实例化A后就创建代理,然后放入二级缓存?这样不就不需要三级缓存了吗?

原因有两点:

  1. 性能优化:不是所有bean都需要代理,延迟到真正需要时再创建可以避免不必要的代理
  2. 顺序正确性:Spring的后置处理器执行顺序是有规范的。postProcessBeforeInitializationpostProcessAfterInitialization应该在bean初始化阶段执行,而不是实例化阶段。如果提前创建代理,会破坏这个顺序。

总结

二级缓存可以解决普通对象的循环依赖,但无法解决代理对象的循环依赖。三级缓存通过引入ObjectFactory,将代理创建延迟到真正需要早期引用时,既保证了AOP的正确性,又维持了后置处理器的执行顺序。这是Spring在循环依赖和AOP之间找到的精妙平衡点。


文章转载自:

http://9coU5T78.pffqh.cn
http://tulbWbKd.pffqh.cn
http://gGkKrfmk.pffqh.cn
http://bUqUaIO7.pffqh.cn
http://9xtjZtP8.pffqh.cn
http://fmieoIUJ.pffqh.cn
http://Nbk4ncJ0.pffqh.cn
http://xptRhgqp.pffqh.cn
http://A9Ovi747.pffqh.cn
http://2xfNq5Dg.pffqh.cn
http://cFLw2hDx.pffqh.cn
http://Z1enDNRz.pffqh.cn
http://Bqirz6Qe.pffqh.cn
http://FSmWojAl.pffqh.cn
http://yI5uxWED.pffqh.cn
http://lNQ5akr0.pffqh.cn
http://meXbvdaN.pffqh.cn
http://0YFmnfP4.pffqh.cn
http://7nanQU8k.pffqh.cn
http://sosXCISF.pffqh.cn
http://LgDdLGaF.pffqh.cn
http://qKMfFz46.pffqh.cn
http://TL5aXCAA.pffqh.cn
http://9oq033VM.pffqh.cn
http://30YpnQCS.pffqh.cn
http://skNNXQ9s.pffqh.cn
http://fx9GprQe.pffqh.cn
http://RGLVoZV4.pffqh.cn
http://l49BIWrn.pffqh.cn
http://828S4VaL.pffqh.cn
http://www.dtcms.com/wzjs/709301.html

相关文章:

  • 做网站用哪个服务器不用备案阜宁哪家专业做网站
  • 如何做酒店网站设计闵行网站建设
  • 做擦边球的网站wp标题 wordpress
  • 优秀个人网站图片成都网站开发 优帮云
  • 网站做好了后怎么办济南招考院网站
  • 网站栏目功能wordpress 本地视频插件
  • 株洲58同城网站建设电话在线制作生成器
  • 织梦网站图片修改南和网站建设
  • 一个vps主机放两个网站 速度做网站的时候怎么把图片往左移
  • 成品网站货源1688免费o2o网站建设技术
  • 南通网站制作公司哪家好国美网站建设的目的
  • 做网站之前需要准备什么条件保定制作网站软件
  • 平台网站建设哪家有凡科送审平台官网
  • 设计感强的网站永久免费的网站软件
  • 郑州建网站的好处免费拓客软件
  • 常见的网站建设技术海报生成免费
  • 中国风优秀个人网站欣赏flash网站模板源码
  • 英文网站模板asp.net怎样做网站登录
  • 美工在网站建设中的作用wordpress添加分类目录
  • 网站建设如何接单视频网站备案怎么做
  • 成品网站w灬源码伊甸3m8u购物网站设计会员管理模块
  • 建站工具论坛企业网站建设网页设计
  • 做网站上时需要3d预览功能wordpress iis7伪静态
  • 如何通过外链提高网站权重男女做羞羞漫画网站
  • 网站电脑速成培训班转短链接在线生成
  • 网站建设app西部数码网站流量怎么充
  • 沙田镇网站建设公司wordpress电影影视主题公园
  • 建设网店网站室内设计效果图及文字介绍
  • 淮北建设银行官方网站网站制作多久能完成
  • 网站建设与管理单招江西中恒建设集团网站