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

小型教育网站的开发建设开题报告收录批量查询工具

小型教育网站的开发建设开题报告,收录批量查询工具,教育培训网站建设,商丘做网站哪个好在 Spring 框架的开发过程中,循环依赖是一个常见且需要谨慎处理的问题。今天咱们就来深入探讨一下 Spring 是如何解决循环依赖的,以及哪些情况下循环依赖是无法解决的。 一、什么是循环依赖 循环依赖,简单来说,就是两个或两个以上…

在 Spring 框架的开发过程中,循环依赖是一个常见且需要谨慎处理的问题。今天咱们就来深入探讨一下 Spring 是如何解决循环依赖的,以及哪些情况下循环依赖是无法解决的。

一、什么是循环依赖

循环依赖,简单来说,就是两个或两个以上的 bean 相互持有对方的引用,最终形成一个闭环。比如,A bean 依赖 B bean,而 B bean 又依赖 A bean,这就像两个人互相拉着对方的手,谁也没办法先迈出第一步。在 Spring 中,注入 bean 的方式主要有构造器注入和 field 属性注入,不同的注入方式在面对循环依赖时表现各异。

二、Spring 如何解决 field 属性注入的循环依赖

Spring 解决 field 属性注入循环依赖的核心机制是三级缓存和 Java 的引用传递,同时采用了提前暴露对象和延后设置属性的策略。

假设我们有两个类 A 和 B,它们通过 field 属性注入形成了循环依赖:

收起

java

import org.springframework.stereotype.Service;@Service
public class A {@Autowiredprivate B b;
}@Service
public class B {@Autowiredprivate A a;
}

当 Spring 容器启动创建 bean 时,大致过程如下:

  1. 创建 A 对象并放入三级缓存:Spring 首先通过反射创建 A 对象的实例,这个时候 A 对象还不完整,它的 b 属性还是 null。但 Spring 会把这个 “半成品” A 对象提前暴露到三级缓存(singletonFactories)中。
  2. 触发 B 对象的创建:A 对象需要填充 b 属性,于是去缓存中查找 B 对象。由于此时 B 对象还未创建,就会触发 B 对象的创建流程。
  3. 创建 B 对象并放入三级缓存:B 对象创建后也被放入三级缓存,此时 B 对象的 a 属性同样为空。
  4. 完成 B 对象的属性填充:B 对象在填充 a 属性时,会从缓存中找到之前提前暴露的 A 对象,并完成注入。
  5. 完成 A 对象的属性填充:最后,A 对象从缓存中顺利获取到 B 对象,完成 b 属性的填充。至此,循环依赖问题得以解决。

这里的三级缓存各司其职:

  • 一级缓存(singletonObjects:存放的是完整的、可以直接使用的 bean。从这里取出的 bean,就像是装配好所有零件、可以直接投入使用的机器。
  • 二级缓存(earlySingletonObjects:存放提前暴露的 bean,但这些 bean 还不完整,尚未完成属性注入和执行 init 方法,主要用于解决循环依赖。它就像是半成品,虽然有了大致的框架,但还缺少一些关键的部分。
  • 三级缓存(singletonFactories:对初始化后的 bean 完成 AOP 代理操作。它保证了 bean 的生命周期,确保在合适的时机生成代理,而不是在实例化之后就立即生成,避免影响 bean 的正常功能。

三、Spring 如何解决构造器注入的循环依赖

构造器注入的循环依赖相对复杂一些,Spring 无法像处理 field 属性注入那样直接解决,需要借助一些额外的手段。常见的解决方式有两种:使用@ScopeproxyMode属性和@Lazy注解。

(一)使用 @Scope 的 proxyMode 属性

收起

java

import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;@Service
public class A {private B b;@Autowiredpublic A(B b) {this.b = b;}
}@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Service
public class B {private A a;@Autowiredpublic B(A a) {this.a = a;}
}

@Scope注解用于定义 bean 的作用域,默认是单例(singleton)。通过proxyMode属性可以设置类的代理模式,这里使用ScopedProxyMode.TARGET_CLASS表示使用 CGLIB 动态代理。这种方式下,Spring 通过创建代理对象打破循环依赖,使得 A 和 B 能够顺利创建。

(二)使用 @Lazy 注解

收起

java

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Lazy;@Service
public class A {private B b;@Autowiredpublic A(@Lazy B b) {this.b = b;}
}@Service
public class B {private A a;@Autowiredpublic B(A a) {this.a = a;}
}

@Lazy注解的作用是让 bean 延迟加载。当 A 依赖 B 时,由于 B 被标记为延迟加载,Spring 会创建一个 B 的代理对象 Bproxy 来满足 A 的依赖。这样,A 依赖的是 Bproxy,而不是真实的 B 对象,打破了循环依赖。之后创建 B 时,因为 A 已经存在,B 也能成功创建。

四、无法解决的循环依赖

虽然 Spring 提供了多种解决循环依赖的方法,但有些情况下循环依赖确实无法解决。

最典型的就是构造器注入的循环依赖,如果没有使用上述提到的特殊手段(@ScopeproxyMode属性或@Lazy注解),Spring 在启动时会抛出BeanCurrentlyInCreationException异常。这是因为构造器注入要求在创建 bean 时就完成所有依赖的注入,而循环依赖使得这个过程陷入了死锁,Spring 无法确定先创建哪个 bean。

另外,在一些复杂的自定义 BeanPostProcessor 场景中,如果自定义的后置处理器逻辑与循环依赖相互干扰,也可能导致循环依赖问题无法解决。比如,后置处理器在 bean 初始化过程中对依赖关系进行了错误的修改,使得 Spring 原本的解决机制失效。

五、总结

Spring 通过三级缓存机制巧妙地解决了 field 属性注入的循环依赖问题,同时借助动态代理(@ScopeproxyMode属性和@Lazy注解)来处理构造器注入的循环依赖。然而,我们也要清楚地认识到,并非所有的循环依赖都能被 Spring 轻松化解。在实际开发中,合理设计 bean 之间的依赖关系,避免不必要的循环依赖,才是编写健壮 Spring 应用的关键。希望通过这篇博客,大家对 Spring 的循环依赖问题有更深入的理解,在开发中能够更加游刃有余地应对相关挑战。

http://www.dtcms.com/wzjs/171506.html

相关文章:

  • 国外好的做电视包装的网站亚马逊免费的关键词工具
  • 企业网站制作 南京百度推广的优化软件
  • axcure做网站ui网络营销策划的目的
  • 站长工具 怎么做网站地图百度手机助手下载正版
  • 深圳免费建站百度公司高管排名
  • 免费做ppt网站怎么优化推广自己的网站
  • 成都网站制作电话广告宣传方式有哪些
  • 做网站后台学什么专业外链服务
  • 恩施哪里有做网站的护肤品推广软文
  • 图书类网站开发的背景百度竞价登录入口
  • 网站建设的三网合一百度竞价排名机制
  • 我们不仅仅做网站更懂得网络营销郑州做网站最好的公司
  • 深圳建站服务公司有哪些搜索引擎网站
  • 2022腾讯云网站建设方案书寻找客户的渠道和方法
  • 国内移动端网站做的最好的seo优化网站技术排名百度推广
  • 海外医疗网站建设深圳网站推广公司
  • 百度推广要不要建网站深圳seo优化公司
  • 攸县网站制作公司信息流优化师面试常见问题
  • 用html5制作个人网站网络营销成功的品牌
  • 网站的静态资源服务器怎么做seo排名赚app靠谱吗
  • 为企业做优做强厦门seo外包
  • dw管理动态网站模板下载谷歌海外广告投放推广
  • 搭建一个网站的基本流程个人网站开发网
  • 做网站的没有进项票怎么办网络推广怎么做?
  • 用游戏人物做网站属于侵权吗百度客服电话是多少
  • 为违法网站做推广进去要几年网站搭建公司
  • 简要叙述如何规划建设一个企业网站优化关键词的方法正确的是
  • linux做网站的好处网页设计素材
  • 东莞网站的关键字推广搜索引擎营销方法有哪些
  • 网站建设有哪些平台百度推广客户端下载安装