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

网站建设阿胶膏的作用软件关键词排名

网站建设阿胶膏的作用,软件关键词排名,如何用自己的电脑做网站空间,什么网站可以做外贸什么是 spring 的循环依赖? 首先,认识一下什么是循环依赖,举个例子:A 对象被 Spring 管理,并且引入的 B 对象,同样的 B 对象也被 Spring 管理,并且也引入的 A 对象。这种相互被引用的情况&#…

什么是 spring 的循环依赖?


首先,认识一下什么是循环依赖,举个例子:A 对象被 Spring 管理,并且引入的 B 对象,同样的 B 对象也被 Spring 管理,并且也引入的 A 对象。这种相互被引用的情况,就是所谓的循环依赖

@Component
public class A {@Autowiredprivate B b;
}
@Component
public class B {@Autowiredprivate A a;
}

我们都知道,Spring 是将对象给管理起来,这些对象默认还都是单例的,需要的话从 Spring 中直接取出即可。

1. Spring 是如何存储这些 Bean 呢?

Spring 通过 Map 结构将对象给缓存起来,这里的 Map 其实是分为三个:

  1. 一级缓存(singletonObjects):此缓存中的对象是已经完全创建好的,可以直接使用的 Bean;

    Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    
  2. 二级缓存(earlySingletonObjects):此缓存中存储尚未完全初始化但已经创建了对象实例的 Bean(即提前暴露的 Bean 实例)

    Map<String, Object> earlySingletonObjects = new HashMap<>();
    
  3. 三级缓存(singletonFactories):比较特殊,存放的是 ObjectFactory,这是一个工厂,等到从缓存中取时,会执行其中的 getObject() 方法,来得到代理对象

    Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>()
    

    这样设计是为了在有 AOP 的情况下,可以返回代理对象,而且也能满足循环依赖。

2. 循环依赖的创建过程

  1. 当对象 a 被创建时,就会在缓存中进行查询,先从一级缓存中进行查询,如果没有,接着再从二级缓存中进行查询,如果依旧没用,最后从第三级缓存中查询,如果还是没有,就接着执行后续操作;

  2. 由于缓存中没有 a 对象,就要回到主流程,执行 a 对象的创建

    1. 利用反射创建对象
    2. 这时候就要用到三级缓存,将创建出的对象包装成 ObjectFctory 类型,放到三级缓存中
  3. 填充 a 对象的属性(Bean 的引入也在此执行)

    其中要引入 b 对象,同样也要执行与 a 对象创建相同的流程:

    1. 查询缓存

    2. b 对象的创建:利用反射创建 b 对象,并存入三级缓存中

    3. 填充 b 对象的属性

      此时又要引入 a 对象,由于已经将 a 存储到缓存中,因此这里要执行一些额外的操作(后面说)后,将得到的 a 对象填充到 b 对象中

    4. 初始化

    5. 缓存转移(具体步骤后面说

  4. a 对象初始化

  5. 缓存转移

总体流程大致如下:

3. 补充说明

3.1 在 b 对象创建中填充属性时,从缓存中读取 a 对象要经过什么操作?

参考源码,读取关键部分(红框位置):


首先从三级缓存中获取到 a 对象,由于这个缓存里存放的是 ObjectFactory 类型,并不是真正的对象,这里就要执行 getObject() 方法,从而创建出真正要使用的对象,将得到的真正的对象 a 存入二级缓存中,并将三级缓存中的 a 删除。

3.2 缓存转移的步骤是什么?

此时 b 已经完全创建完毕,所以要将缓存里面的对象进行转移,参考源码:


可以分析出具体操作为:

  1. 将 b 的完整对象放到一级缓存中
  2. 将三级缓存中的 b 移除掉
  3. 将二级缓存中的 b 移除掉(该场景下二级缓存中并没有 b 对象)

a 对象的缓存转移也是同理。

4. 扩展

4.1 第三级缓存的作用?

从上面的执行步骤,可以感觉到三级缓存和里面的 ObjectFactory 类型似乎有点多余,有一级、二级缓存也能搞定循环依赖,三级缓存的意义是什么?

其实主要作用就是为了 AOP。

举例:假如对 b 对象使用了 AOP 切面功能,那么 a 对象引入的 b 对象就必须是 b 对象的代理对象,当 Spring 在没有循环依赖的情况下,是先将普通的完整对象创建好之后,再生成对应的代理对象,然而 Spring 并没有办法提前知道这个对象有没有循环依赖,也不能直接将每个对象都创建出代理对象,所以就需要吧对象包装成 ObjectFactory 类型,提前曝光,等从三级缓存中获取到 ObjectFactory 后,就可以通过 getObject() 方法生成代理对象。

4.2 避免循环依赖的最佳实践

尽管 Spring 提供了循环依赖的解决方案,但在实际开发中应尽量避免循环依赖,因为它可能导致代码耦合度过高、可维护性差等问题。以下是一些避免循环依赖的建议:

  1. 重构代码:将公共逻辑提取到第三个类中,打破循环依赖。
  2. 使用接口或事件驱动:通过接口或事件机制解耦组件间的直接依赖。
  3. 谨慎使用构造器注入:对于可能存在循环依赖的场景,优先使用 Setter 注入

4.3 构造器注入与 Setter 注入的区别

  1. Setter 注入:支持循环依赖。因为 Spring 可以通过三级缓存机制提前暴露部分初始化的 Bean 实例
  2. 构造器注入:不支持循环依赖。原因在于构造器注入要求在创建 Bean 时必须提供所有依赖项,而循环依赖会导致死锁(A 等待 B,B 等待 A)。

因此,如果使用构造器注入,循环依赖会导致 BeanCurrentlyInCreationException 异常。

BeanCurrentlyInCreationException 异常:表示在尝试实例化一个 Bean 时,Spring 容器检测到正在创建的 Bean 已经在创建过程中,导致循环依赖。这种异常通常是由于循环依赖问题引起的。

5. 总结

Spring 通过三级缓存机制解决了单例 Bean 之间的循环依赖问题,但对于原型 Bean 或构造器注入的场景,Spring 无法解决循环依赖。开发时应尽量避免循环依赖,保持代码的清晰性和可维护性

http://www.cadmedia.cn/news/10807.html

相关文章:

  • app怎么推广运营河北百度seo关键词排名
  • 网站建设 创意视频seo推广思路
  • 清新县城乡规划建设局网站交换友链
  • css网站怎么做google框架一键安装
  • 做网站构架用什么软件定制网站开发
  • 网站建设vi设计万物识别扫一扫
  • 手表网站大全方象科技专注于什么领域
  • 无极领域0基础12天精通网站建设万网app下载
  • web开发框架有哪些成都网站优化seo
  • 广州住房和城乡建设局官网培训如何优化网站
  • 政府机关网站模板代运营网店公司
  • 福州网站关键词推广怀化网站seo
  • 柯林wap建站程序个人版cba赛程
  • 网站设计公司模板下载安徽百度seo公司
  • 网站规划与设计一千字做网站的软件
  • 企业的营销型网站建设整合营销传播方案
  • 贵州住房城乡建设厅官方网站在哪里可以做百度推广
  • 最漂亮的网页网站优化及推广
  • 江苏南通疫情最新消息今天封城了深圳优化怎么做搜索
  • 推荐武汉手机网站建设青岛设计优化公司
  • 给别人做网站赚钱吗培训学校招生方案
  • 网址导航网站网站功能优化的方法
  • 晋城做网站公司营销网站建设都是专业技术人员
  • 建设个网站seo优化有哪些
  • 河南郑州网站制作公司做免费推广的平台
  • 网站建设及目标口碑营销的名词解释
  • 建设银行荆门招聘网站淘宝客推广有效果吗
  • 保定专业网站建设开发公司百度关键词搜索排名
  • 新手如何做英文网站赚美元网站seo优化方案项目策划书
  • 青岛品牌网站建设万网官网入口