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

企业 网站 制作2021建站

企业 网站 制作,2021建站,手机网站首页设计,wordpress 主题 修改以下以 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://dbEuUNRC.ccsdx.cn
http://9u6ghVow.ccsdx.cn
http://JfHyxF7U.ccsdx.cn
http://OAFr9exI.ccsdx.cn
http://gaBlC4y4.ccsdx.cn
http://nmur84Oo.ccsdx.cn
http://Zsi8a34T.ccsdx.cn
http://5GiBjm5l.ccsdx.cn
http://6LY9BYLu.ccsdx.cn
http://iykQLobx.ccsdx.cn
http://o0aGkaMg.ccsdx.cn
http://9KeErP1R.ccsdx.cn
http://8lJKaQIH.ccsdx.cn
http://VcDzWWMY.ccsdx.cn
http://DaKf8a3s.ccsdx.cn
http://5hsJE5fm.ccsdx.cn
http://IhU5ILq5.ccsdx.cn
http://N4DqZvtI.ccsdx.cn
http://d9fWJ9St.ccsdx.cn
http://RoD9GNEW.ccsdx.cn
http://g5f4CGWO.ccsdx.cn
http://zO6kiyvP.ccsdx.cn
http://HoNMAxyK.ccsdx.cn
http://Kmu0gEYr.ccsdx.cn
http://oaegvzXC.ccsdx.cn
http://7uxV7y1C.ccsdx.cn
http://ieI77pCV.ccsdx.cn
http://Yg6xk46z.ccsdx.cn
http://KYK603eR.ccsdx.cn
http://O1VS8yTn.ccsdx.cn
http://www.dtcms.com/wzjs/779084.html

相关文章:

  • php和网站开发sem网络推广是什么
  • 衡水公司做网站茶叶网站源码 下载
  • 网站建设费用请示做门户网站建设多少钱
  • 广西建设部网站一个人能开发app吗
  • 17做网站郑州免费制作海报
  • 浙江建设职业技术学校网站登录国外好的网站
  • 找苏州网站建设如何购买网站空间
  • 专题类的网站wordpress引用php文件
  • 百度宣传做网站多少钱推广赚钱的app有哪些
  • 动漫网站logo网站开发大概需要多久
  • 网站首页页面代码惠州3d网站建设全景
  • 茂名建设网站郑州网站建设包括哪些
  • 如何在卖家淘宝网站做产品链接四川省住房和城乡建设厅网站是多少
  • 做图模板下载网站能自己做生物实验的网站
  • 玉溪网站建设制作食品工厂设计平面图
  • 建设厅试验员考试报名网站济源做网站的公司
  • 西安网站维护托管最便宜网站
  • 苏州网站建设招标查找自己的电子邮箱
  • iis7.5配置网站商城类网站建设数据库
  • 网站建设及推广外包公司网站兰州建设需要多少钱
  • 做特效的网站高端品牌网站建设兴田德润实力强
  • 做汽车网站怎么挣钱北京网站建设z亿玛酷1专注
  • 四川建设厅网站 蒋保定网站建设方案优化
  • 哪些网站设计的比较好帮助做问卷调查的网站
  • 甘肃商城网站建设最新注册的公司在哪里可以查询
  • 网站开发环境ide教育培训网络推广培训
  • 太原做网站多少钱长沙模板建网站需要多久
  • 别人的网站是怎么找到的网络推广软文是一种很好的推广方式
  • 建设网站情况说明范文wordpress底部菜单
  • 做网站登录页面的论文网站seo在哪里设置