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

内蒙古网站建设流程推广策划方案

内蒙古网站建设流程,推广策划方案,多用户wordpress插件,中建八局第一建设有限公司资质有代理对象的循环依赖时,如何确保代理对象能够正确持有原始对象的所有属性赋值结果? 有代理对象的循环依赖时,如何确保代理对象能够正确持有原始对象的所有属性赋值结果?一、问题背景二、解答核心三、Spring 代理对象与属性赋值的…

有代理对象的循环依赖时,如何确保代理对象能够正确持有原始对象的所有属性赋值结果?

  • 有代理对象的循环依赖时,如何确保代理对象能够正确持有原始对象的所有属性赋值结果?
    • 一、问题背景
    • 二、解答核心
    • 三、Spring 代理对象与属性赋值的核心机制
      • 1. 代理对象的本质
      • 2. 属性赋值的对象
      • 3. 三级缓存的作用
      • 4. 关键点:代理对象如何“继承”属性
    • 四、详细流程分析
      • 1. 阶段一:创建 Bean A
      • 2. 阶段二:创建 Bean B
      • 3. 阶段三:完成 Bean A 的创建
      • 4. 阶段四:代理对象访问属性
    • 五、为什么代理对象能正确获取属性值?
      • 1. CGLIB 代理的实现
      • 2. JDK 动态代理的实现
      • 3. Spring 的缓存管理

源码见:mini-spring

在这里插入图片描述

有代理对象的循环依赖时,如何确保代理对象能够正确持有原始对象的所有属性赋值结果?

一、问题背景

在 Spring 解决有代理对象的循环依赖时,核心是通过三级缓存(singletonFactories)和 SmartInstantiationAwareBeanPostProcessorgetEarlyBeanReference 方法提前生成代理对象(如 AProxy)。但是,代理对象生成时,原始对象(如 A)可能尚未完成属性注入(例如 A 的属性 b 尚未赋值)。你的疑问是:

  • 提前生成的代理对象 AProxy 是基于“半成品”原始对象 A 创建的,此时 A 的属性(如 b)尚未赋值。
  • 在后续 A 的创建过程中,属性注入是针对原始对象 A 完成的。
  • 最终容器中的 AProxy 如何确保其属性(如 b)是正确赋值的?

二、解答核心

Spring 的代理对象(如通过 CGLIB 或 JDK 动态代理生成的 AProxy)通常是对原始对象 A 的包装,而不是一个独立的对象。代理对象通过持有原始对象的引用(称为 target),在调用时将请求委托给原始对象。因此,对原始对象 A 的属性赋值会直接反映到代理对象 AProxy,因为代理对象内部的逻辑依赖于原始对象的状态。

以下从机制和流程两个方面详细解答。


三、Spring 代理对象与属性赋值的核心机制

1. 代理对象的本质

  • JDK 动态代理:基于接口,代理对象实现与目标对象相同的接口,内部通过 InvocationHandler 持有原始对象的引用。
  • CGLIB 代理:基于子类,代理对象是原始对象的子类,继承了原始对象的字段,并通过 super 访问或直接持有原始对象的引用。
  • 在 Spring 的循环依赖场景中,代理对象(AProxy)通常通过 CGLIB 生成,代理对象会直接包含原始对象 A 的字段,或者通过某种方式(如委托模式)访问原始对象的字段。

2. 属性赋值的对象

  • 在 Spring 的 Bean 创建过程中,属性注入(如 @Autowired 或 Setter 注入)是直接针对原始对象 A 完成的
  • 代理对象 AProxy 本身并不直接参与属性注入,而是通过引用原始对象 A 来访问其属性值。

3. 三级缓存的作用

  • 三级缓存(singletonFactories)存储 ObjectFactory,通过 getEarlyBeanReference 提前生成代理对象 AProxy。
  • 二级缓存(earlySingletonObjects)保存提前暴露的代理对象 AProxy,供依赖方(如 B)使用。
  • 一级缓存(singletonObjects)最终存储完全初始化的代理对象 AProxy。

4. 关键点:代理对象如何“继承”属性

  • CGLIB 代理:AProxy 是 A 的子类,继承了 A 的所有字段。属性注入直接修改 A 的字段,而 AProxy 作为子类实例,天然持有这些字段值。
  • JDK 动态代理:AProxy 通过 InvocationHandler 持有原始对象 A 的引用,任何对字段的访问(如 getB())都会委托给原始对象 A,从而获取注入的属性值。
  • 因此,无论哪种代理方式,属性注入的结果都会反映在代理对象的行为中,因为代理对象最终依赖原始对象的状态。

四、详细流程分析

让我们以文章中的例子(A 依赖 B,B 依赖 A,且 A 被 AOP 代理)来梳理整个流程,重点说明属性赋值如何传递到代理对象。

1. 阶段一:创建 Bean A

  • 步骤
    • Spring 调用 A 的构造方法,生成原始对象 A(尚未进行属性注入)。
    • 将 A 封装为 ObjectFactory,加入三级缓存(singletonFactories),其中 ObjectFactory.getObject() 调用 getEarlyBeanReference。
    • A 需要注入属性 b(类型为 B),触发 B 的创建。
  • 状态
    • 此时,原始对象 A 的字段 b 为 null。
    • 三级缓存中存储了 A 的 ObjectFactory。

2. 阶段二:创建 Bean B

  • 步骤
    • Spring 创建 B 的原始对象,加入三级缓存。
    • B 需要注入 A(字段 a),Spring 调用 getSingleton(“A”):
      • 一级缓存(singletonObjects)和二级缓存(earlySingletonObjects)中没有 A。
      • 从三级缓存(singletonFactories)获取 A 的 ObjectFactory,调用 getObject()。
      • getEarlyBeanReference 被触发,SmartInstantiationAwareBeanPostProcessor(如 AbstractAdvisorAutoProxyCreator)生成 A 的代理对象 AProxy。
      • AProxy 加入二级缓存(earlySingletonObjects),从三级缓存移除。
    • B 的字段 a 被注入 AProxy,B 完成创建,放入一级缓存。
  • 状态
    • B 的字段 a 持有 AProxy。
    • 原始对象 A 的字段 b 仍为 null,因为 A 的属性注入尚未完成。
    • 二级缓存中存储了 AProxy。

3. 阶段三:完成 Bean A 的创建

  • 步骤
    • 返回到 A 的创建流程,Spring 对原始对象 A 进行属性注入:
      • 调用 Setter 方法(如 setB(B b))或直接通过反射设置字段 b。
      • 从一级缓存获取已创建的 B,注入到原始对象 A 的字段 b。
    • 原始对象 A 的字段 b 现在持有 B 的引用。
    • Spring 继续执行 A 的初始化,调用 BeanPostProcessor 的 postProcessAfterInitialization:
      • 检查 earlyProxyReferences,发现 A 已提前生成代理(AProxy),因此不重复生成。
    • Spring 从二级缓存获取 AProxy,将其放入一级缓存(singletonObjects)
  • 状态
    • 原始对象 A 的字段 b 已注入 B。
    • AProxy 作为 A 的子类(CGLIB)或通过 InvocationHandler 引用 A(JDK 代理),可以访问 A 的字段 b。
    • 一级缓存中的 AProxy 是最终暴露的对象,B 中的字段 a 也指向 AProxy。

4. 阶段四:代理对象访问属性

  • 访问机制
    • 当通过 AProxy 调用方法(如 getB())时:
      • CGLIB 代理:AProxy 继承了 A 的字段,getB() 直接返回 A 的字段 b(已注入 B)。
      • JDK 动态代理:AProxy 的 InvocationHandler 将 getB() 调用委托给原始对象 A,返回字段 b 的值。
    • 因此,AProxy.getB() 返回注入的 B,属性赋值结果成功反映在代理对象上。
  • 结果
    • 容器中的 A 是 AProxy,B 中的 a 也是 AProxy,引用一致。
    • AProxy 能够正确访问原始对象 A 的属性值(如 b),代理逻辑(如 AOP 切面)也能正常触发。

五、为什么代理对象能正确获取属性值?

1. CGLIB 代理的实现

  • 机制
    • CGLIB 生成的 AProxyA 的子类,继承了 A 的所有字段(如 private B b)。
    • 属性注入直接修改原始对象 A 的字段 b,而 AProxy 作为子类实例,共享这些字段值。
    • 调用 AProxy.getB() 时,直接访问继承的字段 b,返回注入的 B
  • 代码示例(简化):
    class A {private B b;public B getB() { return b; }public void setB(B b) { this.b = b; }
    }
    class AProxy extends A {// 继承了 A 的字段 b@Overridepublic B getB() {// AOP 拦截逻辑return super.getB(); // 访问父类 A 的字段 b}
    }
    
  • 结论
    • 属性注入修改了原始对象 A 的字段,而 AProxy 继承了这些字段,因此能直接访问注入的属性值。

2. JDK 动态代理的实现

  • 机制
    • JDK 动态代理生成 AProxy,实现与 A 相同的接口(如 IA),并通过 InvocationHandler 持有原始对象 A 的引用。
    • 属性注入修改原始对象 A 的字段 b
    • 调用 AProxy.getB() 时,InvocationHandler 将调用转发到原始对象 A,返回字段 b 的值。
  • 代码示例(简化):
    interface IA {B getB();
    }
    class A implements IA {private B b;public B getB() { return b; }public void setB(B b) { this.b = b; }
    }
    class AProxyHandler implements InvocationHandler {private A target;AProxyHandler(A target) { this.target = target; }public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// AOP 拦截逻辑return method.invoke(target, args); // 转发到原始对象 A}
    }
    
  • 结论
    • 属性注入修改了原始对象 A 的字段,AProxy 通过 InvocationHandler 访问 A 的字段,因此能获取注入的属性值。

3. Spring 的缓存管理

  • Spring 确保代理对象 AProxy 是最终暴露的对象(一级缓存和 B 的字段 a 都引用 AProxy)。
  • 属性注入发生在原始对象 A 上,但代理对象通过继承(CGLIB)或委托(JDK 代理)访问这些属性值,确保行为一致。
http://www.dinnco.com/news/27217.html

相关文章:

  • 设计师网站导航杭州网站seo推广
  • 微信网站设计分析代运营哪家比较可靠
  • 云南做网站郑州seo教程
  • 好用的网站管理系统营销助手
  • wordpress文章分页共多少页青岛网站制作seo
  • 重庆网站制作公司靠谱吗郑州seo顾问外包
  • 如何做网页宣传网站排名优化外包
  • 网站开发开票交税教育机构在线咨询
  • 微信网站测试网站seo快速优化
  • 微信营销和网站建设电商网站开发平台有哪些
  • 自己怎么做免费网站一篇好的营销软文
  • 基于jsp的精品课程网站建设semir
  • 做网站反链360识图
  • 百度网盘怎样做网站网络营销方案案例
  • 网站生成软件推广营销app
  • 营销型网站建设方案演讲ppt2022最新热点事件及点评
  • 云南省住房和城乡建设厅网站seo推广公司招商
  • 网站建设高清图片网络推广合作协议
  • 网站上的滚动条是如何做的东莞seo黑帽培训
  • 新广告法 做网站的深圳关键词排名seo
  • 律师网站建设推广如何seo搜索引擎优化
  • 深圳做网站找哪家好合肥关键词排名工具
  • 常州网站推广多少钱网络运营工作内容
  • 青岛开发区网站建设自己如何优化网站排名
  • 黄石网站建设价格企业推广软件
  • 制作一个公司网站用vs怎么做推广引流最快的方法
  • 应用开发是什么网页优化最为重要的内容是
  • 网站定制开发前期要有一定的规划网络推广app
  • 不改变网站怎么做关键词优化百度店铺怎么开通
  • 网站内页产品做跳转重庆网站seo推广公司