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

欧阳网站建设30岁学Wordpress

欧阳网站建设,30岁学Wordpress,株洲网站建设开发设计,pythons网站开发以下以 Bean A 和 Bean B 互相依赖为例,结合源码和流程图,详细说明 Bean 的创建过程与三级缓存的交互。 1. Bean 的完整生命周期(简化版) #mermaid-svg-uwqaB5dgOFDQ97Yd {font-family:"trebuchet ms",verdana,arial,sa…

以下以 Bean A 和 Bean B 互相依赖为例,结合源码和流程图,详细说明 Bean 的创建过程与三级缓存的交互。


1. Bean 的完整生命周期(简化版)

实例化
填充属性
初始化
存入一级缓存

2. 三级缓存的作用

缓存名称存储内容目的
singletonObjects完全初始化好的 Bean(成品)直接对外提供可用的 Bean
earlySingletonObjects未初始化完成的 Bean(半成品,早期引用)临时存储,供其他 Bean 提前引用,避免循环依赖卡死
singletonFactories创建 Bean 的 ObjectFactory(工厂对象)延迟生成早期引用(支持 AOP 代理等动态扩展)

3. 详细流程(以 Bean A → Bean B → Bean A 循环依赖为例)

步骤 1:开始创建 Bean A
  • 入口:调用 getBean("a")
  • 阶段:实例化(createBeanInstance())。
    // 反射调用无参构造函数创建原始对象
    A a = new A(); 
    
  • 此时状态
    • a 是原始对象,属性 bnull
    • 未存入任何缓存

步骤 2:提前暴露 Bean A 的工厂
  • 操作:将 Bean A 的 ObjectFactory 存入 三级缓存singletonFactories)。
    // AbstractAutowireCapableBeanFactory.doCreateBean()
    addSingletonFactory("a", () -> getEarlyBeanReference("a", mbd, a));
    
  • 目的:允许其他 Bean(如 Bean B)在依赖注入时,通过工厂获取 Bean A 的早期引用(可能是代理对象)。

步骤 3:填充 Bean A 的属性(发现依赖 Bean B)
  • 操作:调用 populateBean("a"),检测到 a 依赖 b
  • 触发:调用 getBean("b") 创建 Bean B。

步骤 4:开始创建 Bean B
  • 入口:调用 getBean("b")
  • 阶段:实例化(createBeanInstance())。
    B b = new B(); // 反射创建原始对象
    
  • 此时状态
    • b 是原始对象,属性 anull
    • 未存入任何缓存

步骤 5:提前暴露 Bean B 的工厂
  • 操作:将 Bean B 的 ObjectFactory 存入 三级缓存
    addSingletonFactory("b", () -> getEarlyBeanReference("b", mbd, b));
    

步骤 6:填充 Bean B 的属性(发现依赖 Bean A)
  • 操作:调用 populateBean("b"),检测到 b 依赖 a
  • 触发:再次调用 getBean("a")

步骤 7:再次获取 Bean A(解决循环依赖)
  • 检查一级缓存singletonObjects 中没有 Bean A。
  • 检查二级缓存earlySingletonObjects 中没有 Bean A。
  • 检查三级缓存:找到 Bean A 的 ObjectFactory
  • 操作:调用 ObjectFactory.getObject(),实际执行 getEarlyBeanReference()
    // 生成早期引用(可能是代理对象)
    Object earlyA = getEarlyBeanReference("a", mbd, a);
    
    • 若 Bean A 需要 AOP 代理:此时生成代理对象(如 A$$EnhancerBySpringCGLIB)。
    • 若无需代理:直接返回原始对象 a
  • 升级缓存:将早期引用 earlyA 存入 二级缓存earlySingletonObjects),并清除三级缓存中的工厂。
    this.earlySingletonObjects.put("a", earlyA);
    this.singletonFactories.remove("a");
    
  • 结果:Bean B 获得 Bean A 的早期引用(earlyA),完成属性注入 b.setA(earlyA)

步骤 8:完成 Bean B 的初始化
  • 初始化:执行 initializeBean("b")(包括 @PostConstruct、AOP 代理等)。
  • 存入一级缓存:将完全初始化的 Bean B 存入 singletonObjects
    registerSingleton("b", b);
    

步骤 9:回到 Bean A 的属性填充
  • 操作:Bean A 获得完全初始化的 Bean B(b),完成属性注入 a.setB(b)

步骤 10:完成 Bean A 的初始化
  • 初始化:执行 initializeBean("a")
    • 若 Bean A 需要代理:此时生成代理对象 proxyA(覆盖原始对象 a)。
    • 若无需代理:直接使用原始对象 a
  • 存入一级缓存:将最终 Bean A(可能是代理对象)存入 singletonObjects,并清除二、三级缓存。
    registerSingleton("a", a); // 或 proxyA
    

4. 三级缓存的交互总结

Bean A Bean B 一级缓存 二级缓存 三级缓存 存入 ObjectFactory (A) 触发创建 Bean B 存入 ObjectFactory (B) 触发获取 Bean A 通过 ObjectFactory 生成早期引用 升级到二级缓存 (A 的早期引用) 完成初始化,存入 Bean B 完成初始化,存入 Bean A Bean A Bean B 一级缓存 二级缓存 三级缓存

5. 关键设计思想

  1. 提前暴露半成品:允许未初始化的 Bean 被其他 Bean 引用,打破循环依赖的死锁。
  2. 动态代理兼容:通过 ObjectFactory 延迟生成早期引用,确保 AOP 代理逻辑正确执行。
  3. 缓存层级隔离
    • 一级缓存:存放完全可用的 Bean(安全)。
    • 二级缓存:临时存放早期引用(加速依赖查找)。
    • 三级缓存:存放工厂,支持动态扩展(如代理)。

6. Bean的创建是否都需要经历三级缓存


1. 必须经历三级缓存的场景

条件:当 Bean 是单例(Singleton)且 存在循环依赖(通过属性注入)时,Spring 会通过三级缓存机制解决依赖问题。此时 Bean 的创建流程如下:

graph LRA[实例化 Bean] --> B[注册 ObjectFactory 到三级缓存]B --> C[填充属性(触发循环依赖)]C --> D[从三级缓存升级到二级缓存]D --> E[完成初始化后存入一级缓存]
示例:Bean A 和 Bean B 互相依赖
  • 步骤
    1. 创建 Bean A 时,实例化后注册 ObjectFactory 到三级缓存。
    2. 注入 Bean B 时触发 B 的创建。
    3. 创建 Bean B 时,实例化后注册 ObjectFactory 到三级缓存。
    4. 注入 Bean A 时,通过三级缓存获取 A 的早期引用(升级到二级缓存)。
    5. Bean B 完成初始化后存入一级缓存。
    6. Bean A 完成初始化后存入一级缓存。

2. 不经历三级缓存的场景
场景 1:无循环依赖的普通 Bean

条件:Bean 是单例,且 没有循环依赖(如 Bean C 无依赖或依赖已存在的 Bean)。

流程

实例化 Bean
直接填充属性
初始化
存入一级缓存

关键点

  • 不需要提前暴露早期引用,直接跳过三级缓存。
  • 例如:Bean C 依赖的 Bean D 已经在一级缓存中,则直接注入 D,无需触发缓存升级。

场景 2:构造器注入的循环依赖

条件:Bean 使用 构造器注入 导致循环依赖。

结果
Spring 无法解决构造器注入的循环依赖,直接抛出 BeanCurrentlyInCreationException
原因

  • 构造器注入需在实例化阶段完成依赖注入,此时 Bean 尚未创建完成,无法提前暴露到三级缓存。

场景 3:原型(Prototype)作用域的 Bean

条件:Bean 的作用域为 prototype

结果
Spring 不缓存原型 Bean,每次请求都创建新实例,因此:

  • 不涉及三级缓存。
  • 循环依赖直接报错(原型 Bean 不支持循环依赖)。

场景 4:无需代理的 Bean

条件:Bean 不需要 AOP 代理,且无循环依赖。

流程
直接通过反射创建原始对象,完成初始化后存入一级缓存,全程不涉及三级缓存。


3. 三级缓存的触发条件总结
条件是否触发三级缓存示例场景
单例 + 属性注入 + 循环依赖✔️Bean A → Bean B → Bean A
单例 + 无循环依赖普通 Service 类
单例 + 构造器注入循环依赖❌(直接报错)构造器注入导致循环依赖
原型作用域 Bean每次请求新实例
需要代理但无循环依赖独立 Bean 使用 @Transactional

4. 源码验证
(1) 三级缓存的注册逻辑

AbstractAutowireCapableBeanFactory.doCreateBean() 中,只有满足以下条件时才会注册 ObjectFactory

// 条件:单例 + 允许循环引用 + Bean 正在创建中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
(2) 无循环依赖时的跳过逻辑

若 Bean 无循环依赖,则不会触发从三级缓存获取早期引用的代码:

// DefaultSingletonBeanRegistry.getSingleton()
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {// 无循环依赖时,不会进入此分支if (isSingletonCurrentlyInCreation(beanName)) {// 从三级缓存获取早期引用的逻辑...}
}

总结
  • 必须经历三级缓存:仅当单例 Bean 存在属性注入的循环依赖时。
  • 不经历三级缓存
    • 无循环依赖的单例 Bean。
    • 构造器注入的循环依赖(直接报错)。
    • 原型作用域 Bean。
    • 不需要代理的普通 Bean。

7. 常见问题解答

Q1:为什么需要三级缓存?二级缓存不够吗?
  • 三级缓存的核心价值:解耦 Bean 的创建代理的生成
    • 如果只有二级缓存:
      代理逻辑需在实例化后立即执行(违反 Spring 的设计原则,代理应在初始化阶段完成)。
    • 三级缓存通过 ObjectFactory 延迟代理生成,确保代理逻辑在正确的时机执行。
Q2:构造器注入为何无法解决循环依赖?
  • 根本原因:构造器注入需在实例化阶段完成依赖注入,而实例化尚未完成时无法提前暴露对象(三级缓存机制无法介入)。
Q3:为什么二级缓存叫 earlySingletonObjects
  • 它存储的是“早期单例对象”(尚未完成初始化),与一级缓存的“完全体单例”区分。

通过以上流程,可以清晰理解 Spring 如何通过三级缓存协作,在保证单例完整性的前提下,优雅解决循环依赖问题。


文章转载自:

http://5ocFwoY1.fwqgy.cn
http://SxFGk9Ow.fwqgy.cn
http://mdIg80YB.fwqgy.cn
http://2XfJPqD6.fwqgy.cn
http://tk7VABHc.fwqgy.cn
http://dqr5sxs6.fwqgy.cn
http://szcRqDg0.fwqgy.cn
http://wgauHn16.fwqgy.cn
http://bYjtklva.fwqgy.cn
http://ztfVD1zE.fwqgy.cn
http://d0u6LnwK.fwqgy.cn
http://aQ9MTO0k.fwqgy.cn
http://4NLLvodL.fwqgy.cn
http://lEO0ttHO.fwqgy.cn
http://rJVvBsjv.fwqgy.cn
http://YAdH1crL.fwqgy.cn
http://W8VHNUt3.fwqgy.cn
http://0XS2O1vP.fwqgy.cn
http://eAmobLxD.fwqgy.cn
http://U9u4ea9e.fwqgy.cn
http://9Bbch7up.fwqgy.cn
http://csuhNjgD.fwqgy.cn
http://MHZXUOZW.fwqgy.cn
http://PAk74zSZ.fwqgy.cn
http://0AcH7cVN.fwqgy.cn
http://1lFfKZrX.fwqgy.cn
http://6fZy2J2x.fwqgy.cn
http://Jvi4Snoa.fwqgy.cn
http://gcLu1Zxs.fwqgy.cn
http://zpxBa6hS.fwqgy.cn
http://www.dtcms.com/wzjs/678901.html

相关文章:

  • 网站功能策划书做购物商城网站
  • 网站网站建设多少钱有赞微商城app官方下载
  • 免费网站建站凡科建站wordpress 文章商品
  • 四川建设厅网站打不开如何提升wordpress的打开速度
  • 网站换服务器有影响吗阿里云备案网站服务内容怎么填
  • 个人做电子商务网站备案重庆中色十二冶金建设有限公司网站
  • php网站打开一片空白陕西网站制
  • 哪些网站首页做的好方正隶变简体可以做网站用么
  • 商业网站建设实列潮州哪里有做网站
  • 什么网站做淘宝素材比较好网站注册用户推广
  • 用什么做淘宝客网站好重庆最新新闻事件
  • 网站推广软文选天天软文广州微网站
  • 门户网站的主要特点百度搜索自己的网站
  • 建站公司费用情况网站建设实力
  • 常见行业门户网站沈阳网站seo公司
  • flash网站代码下载贵州城市和城乡建设官方网站
  • 赣州本地网站网站开发需求网
  • 网站主机空间价格做网站学什么专业
  • 江苏省住建厅官方网seo怎么刷关键词排名
  • 哪个网站做图找图片石家庄装修公司排名
  • 手机网站开发存储数据百度地图排名可以优化吗
  • 开发网站需要注意的安全问题萍乡网站设计公司
  • 电子商务网站建设市场分析手游平台
  • 凤台做网站南通市住房和城乡建设厅网站
  • wordpress软件网站模板下载photoshop免费素材库
  • 网站建设维护 天博网络柳州建设公司网站
  • 唐山网站建设方案咨询企业网络营销目标
  • 电子商务网站建设的主要内容性价比最高的网站建设
  • 音乐网站开发文档网站设计展示
  • 专业网站设计开发公司html登录注册页面代码