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

中山网站制作套餐南京网站制作系统

中山网站制作套餐,南京网站制作系统,wordpress天气插件,mx wordpressA 需要 B,而 B 又需要 A,形成一个循环依赖。 1. Spring 如何解决循环依赖? Spring 通过三级缓存机制解决了循环依赖问题,具体步骤如下: 实例化阶段: 当容器创建一个 Bean 时,首先会调用其无参…

A 需要 B,而 B 又需要 A,形成一个循环依赖。

1. Spring 如何解决循环依赖?

Spring 通过三级缓存机制解决了循环依赖问题,具体步骤如下:

  1. 实例化阶段

    • 当容器创建一个 Bean 时,首先会调用其无参构造函数完成实例化(即分配内存,但未进行属性注入)。
    • 实例化完成后,将该 Bean 的“早期引用”(尚未完全初始化的对象)放入三级缓存中。
  2. 属性注入阶段

    • 在为当前 Bean 注入属性时,如果发现依赖的 Bean 尚未完全初始化,则从三级缓存中获取其“早期引用”,完成属性注入。
  3. 初始化阶段

    • 属性注入完成后,执行 Bean 的初始化方法(如 @PostConstruct 或 InitializingBean.afterPropertiesSet())。
    • 初始化完成后,将该 Bean 从三级缓存移动到一级缓存,并清除二级和三级缓存。

三级缓存的具体作用

  1. 一级缓存(singletonObjects

    • 存储完全初始化后的 Bean 实例。
    • 当一个 Bean 完成所有属性注入和初始化后,它会被放入一级缓存中,供后续依赖使用。
  2. 二级缓存(earlySingletonObjects

    • 存储“早期引用”(尚未完全初始化的 Bean 实例)。
    • 如果某个 Bean 在初始化过程中被其他 Bean 依赖,则会从二级缓存中获取其“早期引用”,完成属性注入。
  3. 三级缓存(singletonFactories

    • 存储 Bean 的工厂对象(ObjectFactory),用于动态生成代理对象或其他扩展功能。
    • 三级缓存的主要作用是支持 AOP 动态代理等复杂场景。例如,当一个 Bean 需要被代理时,Spring 会在三级缓存中通过工厂动态生成代理对象。

三级缓存的工作流程

以下是一个典型的循环依赖解决过程:

  1. 实例化阶段

    • 创建 Bean 的实例(调用无参构造函数),但不进行属性注入。
    • 将该 Bean 的工厂对象(ObjectFactory)放入三级缓存中。
  2. 属性注入阶段

    • 如果当前 Bean 需要依赖另一个 Bean,而该 Bean 尚未完全初始化,则从三级缓存中获取其工厂对象,并生成“早期引用”。
    • 将生成的“早期引用”放入二级缓存中,供当前 Bean 使用。
  3. 初始化阶段

    • 属性注入完成后,执行 Bean 的初始化方法(如 @PostConstruct 或 InitializingBean.afterPropertiesSet())。
    • 初始化完成后,将该 Bean 从二级缓存移动到一级缓存,并清除三级缓存和二级缓存中的相关记录。

2.为什么需要三级缓存?一级和二级不够吗?

一级缓存的问题
  • 一级缓存只能存储完全初始化后的 Bean。如果在初始化过程中发生循环依赖,无法从一级缓存中获取尚未完全初始化的 Bean。
二级缓存的问题
  • 二级缓存可以存储“早期引用”,但如果涉及动态代理(如 AOP),则需要额外的机制来生成代理对象。二级缓存无法动态生成代理对象,因此需要三级缓存。
三级缓存的优势
  • 三级缓存通过工厂模式动态生成代理对象,确保在复杂的依赖关系中,Bean 的状态一致且正确。
  • 三级缓存的设计使得 Spring 能够支持更多的扩展功能(如 AOP 动态代理)。

三级缓存的好处和坏处

好处
  1. 支持复杂的依赖关系

    三级缓存允许在 Bean 的生命周期中动态生成代理对象(如 AOP 动态代理),从而支持更复杂的场景。
  2. 保证线程安全

    三级缓存的设计使得在多线程环境下,Bean 的创建和依赖注入更加安全。
  3. 灵活性

    三级缓存提供了一个灵活的机制,可以在不同阶段对 Bean 的状态进行控制。
坏处
  1. 增加复杂性

    三级缓存的引入增加了代码的复杂性,理解和维护成本较高。
  2. 性能开销

    虽然三级缓存的时间复杂度仍然是 O(1)O(1),但多级缓存的管理会增加一定的性能开销。
  3. 潜在问题

    如果开发者滥用循环依赖,可能导致系统设计不合理,甚至出现难以调试的问题。

3.Spring Boot 高版本为什么要手动开启循环依赖?

背景

在 Spring Boot 2.6 及更高版本中,默认情况下禁用了循环依赖(spring.main.allow-circular-references=false)。这是因为循环依赖虽然可以通过三级缓存解决,但它通常是设计上的问题,可能会导致以下问题:

  1. 代码耦合度过高

    循环依赖通常意味着类之间的职责划分不清晰,容易导致代码难以维护。例如,两个类互相依赖可能表明它们的职责没有很好地分离。
  2. 隐藏设计缺陷

    循环依赖可能掩盖了系统设计中的不合理之处。长期来看,这种设计会导致架构变得复杂且难以扩展。
  3. 测试困难

    循环依赖的 Bean 在单元测试中可能更难模拟和测试,因为它们的依赖关系过于紧密。
  4. 性能问题

    循环依赖的解决需要额外的缓存管理和状态检查,这会增加一定的性能开销。
如何手动开启循环依赖?

在 application.properties 或 application.yml 中设置以下配置:

spring.main.allow-circular-references=true

或者通过代码方式启用:

@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication app = new SpringApplication(MyApplication.class);app.setAllowCircularReferences(true);app.run(args);}
}

4.循环依赖的实际案例分析

案例 1:简单的循环依赖

假设有两个类 A 和 B

@Component
public class A {private final B b;@Autowiredpublic A(B b) {this.b = b;}
}@Component
public class B {private final A a;@Autowiredpublic B(A a) {this.a = a;}
}

在这种情况下,Spring 会通过三级缓存解决循环依赖问题。A 和 B 之间的依赖关系会在实例化阶段被正确处理。

案例 2:涉及动态代理的循环依赖

假设 A 是一个事务管理的 Bean,Spring 会为其生成动态代理对象:

@Component
public class A {private final B b;@Autowiredpublic A(B b) {this.b = b;}@Transactionalpublic void doSomething() {// 事务逻辑}
}@Component
public class B {private final A a;@Autowiredpublic B(A a) {this.a = a;}
}

在这种情况下,Spring 会通过三级缓存中的工厂对象动态生成 A 的代理对象,从而解决循环依赖问题。


5.循环依赖的替代方案

为了避免循环依赖,可以采用以下替代方案:

引入中间层

  • 将共同的逻辑抽取到一个新的服务类中,减少直接依赖。
  • @Service
    public class CommonService {public void commonLogic() {// 共同逻辑}
    }@Component
    public class A {private final CommonService commonService;@Autowiredpublic A(CommonService commonService) {this.commonService = commonService;}
    }@Component
    public class B {private final CommonService commonService;@Autowiredpublic B(CommonService commonService) {this.commonService = commonService;}
    }
    

使用事件驱动机制

  • 使用 Spring 的事件发布机制(ApplicationEvent)来解耦组件。
  • @Component
    public class A {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void doSomething() {eventPublisher.publishEvent(new CustomEvent(this));}
    }@Component
    public class B {@EventListenerpublic void handleCustomEvent(CustomEvent event) {// 处理事件}
    }
    

使用懒加载(@Lazy 注解)

  • 通过 @Lazy 注解延迟 Bean 的初始化,从而避免循环依赖问题。
  • @Component
    public class A {private final B b;@Autowiredpublic A(@Lazy B b) {this.b = b;}
    }@Component
    public class B {private final A a;@Autowiredpublic B(@Lazy A a) {this.a = a;}
    }
    

重构代码逻辑

  • 如果两个类之间存在循环依赖,可能表明它们的职责划分不清晰。可以通过重构代码来消除直接依赖。
  • @Service
    public class A {private final CommonLogic commonLogic;@Autowiredpublic A(CommonLogic commonLogic) {this.commonLogic = commonLogic;}public void doSomething() {commonLogic.performLogic();}
    }@Service
    public class B {private final CommonLogic commonLogic;@Autowiredpublic B(CommonLogic commonLogic) {this.commonLogic = commonLogic;}public void doSomethingElse() {commonLogic.performLogic();}
    }@Component
    public class CommonLogic {public void performLogic() {// 共同逻辑}
    }
    

    6.最终总结

    • 循环依赖的本质

      • 循环依赖是指两个或多个 Bean 之间相互依赖,形成一个闭环。
      • Spring 通过三级缓存机制解决了循环依赖问题。
    • 三级缓存的作用

      • 一级缓存:存储完全初始化后的 Bean。
      • 二级缓存:存储“早期引用”(尚未完全初始化的 Bean)。
      • 三级缓存:存储工厂对象,用于动态生成代理对象或其他扩展功能。
    • 为什么需要三级缓存?

      • 一级缓存无法解决循环依赖,因为它只存储完全初始化后的 Bean。
      • 二级缓存无法支持动态代理等复杂场景,因此需要三级缓存。
    • Spring Boot 高版本默认禁用循环依赖的原因

      • 推动更好的设计,避免代码耦合度过高。
      • 减少潜在问题,提高系统性能。
    • 如何手动开启循环依赖?

      • 通过配置文件或代码方式启用 spring.main.allow-circular-references=true
    • 最佳实践

      • 尽量避免循环依赖,采用重构代码、引入中间层或事件驱动机制等方式解决问题。
      • 如果确实无法避免循环依赖,确保它不会导致系统设计问题,并且只在必要的场景下使用。


    文章转载自:

    http://vDeXABKz.yhsrp.cn
    http://I1kyUxnO.yhsrp.cn
    http://0VFdruDu.yhsrp.cn
    http://dignsEU8.yhsrp.cn
    http://wcj0dTjX.yhsrp.cn
    http://LPHoIXMv.yhsrp.cn
    http://mHIogmgJ.yhsrp.cn
    http://IgKgc7JY.yhsrp.cn
    http://2HcSjd1i.yhsrp.cn
    http://iVSTgblp.yhsrp.cn
    http://ltAwvQHp.yhsrp.cn
    http://FyXzUFAS.yhsrp.cn
    http://3dxtV8AX.yhsrp.cn
    http://1NYdvAlz.yhsrp.cn
    http://Zg5lVBOG.yhsrp.cn
    http://CFCbt4C2.yhsrp.cn
    http://x1iZV8M0.yhsrp.cn
    http://JtKfmVpf.yhsrp.cn
    http://OK78d6kD.yhsrp.cn
    http://7ppinR2b.yhsrp.cn
    http://epgL2BhN.yhsrp.cn
    http://q46juVI6.yhsrp.cn
    http://wuxhY0xP.yhsrp.cn
    http://Sfs8RqbK.yhsrp.cn
    http://6znPeRr0.yhsrp.cn
    http://NhNKukqF.yhsrp.cn
    http://SGaYe8XB.yhsrp.cn
    http://uhFSmGDW.yhsrp.cn
    http://Sz3VVUfP.yhsrp.cn
    http://4JJuZHzL.yhsrp.cn
    http://www.dtcms.com/wzjs/639875.html

    相关文章:

  • 如何建设一个普通网页网站有什么网站可以下做闭软件
  • 做公司网站的推广工作怎样企业英语网站
  • html5手机app网站模板室内设计最好的公司
  • 响应式网站在线做推文的网站
  • 做全景图二维码的网站静态手机网站基础
  • 网站改版策划书国外的网站需要备案吗
  • 怎样做网站维护龙岩抖音小程序开发公司
  • 自媒体网站建设要求软件开发培训机构出来的人社保是怎么交的
  • html5网站源代码山东网站建设是什么
  • 如何建设和优化一个网站wordpress导航点不开分类
  • 企业网站建设中存在的问题wordpress视频适应手机
  • 珠海网站建设技术托管什么软件做高级网站
  • 伊春北京网站建设制作一个WordPress主题
  • 网站开发与spark微信推广软件哪个好
  • 深圳做网站网络公司排名WordPress qinmei影视主题
  • 做网站哪个最好wordpress文章入口设置
  • 岳阳网站建设哪里有企业信用信息系统
  • 做网站建设优化的公司有趣的h5创意设计
  • 网站整体结构南宁 建网站 公司
  • 网站备案手续英语做美食网站
  • 网站设计与网页制作模板做一个企业网站价格
  • 二七网站建设潍坊专利申请
  • 网站建设方案计划书人员规划怎么做盗号网站
  • 网站建设怎么添加背景音乐凡科互动官网登录入口网页版
  • 100种增加网站流量的方法wordpress 开发指南
  • 深圳网站设计制作元现在进出重庆最新规定
  • 大连做网站哪家好一点珠海互联网推广
  • wordpress网站描述网站开发 项目内容
  • dede做的网站打不开织梦调用wordpress
  • 网站域名怎么快速备案价格用阿里云做网站注意事项