专业的编程技术博客社区

网站首页 > 博客文章 正文

升级必读:Spring Boot 2.6.0 起循环依赖默认禁用,如何应对?

baijin 2024-12-14 10:28:45 博客文章 7 ℃ 0 评论

在 Spring Boot 的世界里,循环依赖问题一直是开发者们需要谨慎处理的一个话题。从 Spring Boot 2.6.0 开始,官方默认禁用了循环依赖,一旦在应用中存在循环依赖关系,启动时会直接报错。这引起了不少开发者的关注和讨论。那么,什么是循环依赖?默认禁用循环依赖后,我们该如何应对?今天,我们一起深入探讨这些问题。

什么是循环依赖?

循环依赖是指在 Spring IoC 容器中,两个或多个 Bean 之间相互依赖,形成一个闭环。例如,Bean A 依赖于 Bean B,同时 Bean B 依赖于 Bean A。这样的依赖关系如果没有适当的处理,可能会导致应用启动失败或运行时错误。

Spring 中的缓存机制

在 Spring 中,为了管理 Bean 的依赖关系,使用了三级缓存机制来解决循环依赖问题。

  1. 一级缓存(Singleton Objects):用于存放完全初始化好的单例 Bean。
  2. 二级缓存(Early Singleton Objects):用于存放提前曝光的单例 Bean,解决正在创建中但尚未完全初始化的 Bean 的依赖问题。
  3. 三级缓存(Singleton Factories):用于存放 Bean 工厂,通过其获取 Bean 的代理对象,支持 AOP 等功能。

详细的循环依赖处理可以参考“一文彻底明白 Spring 的循环依赖”的第四五六节内容。

Spring Boot 2.6.0 起循环依赖默认禁用 ?

从 Spring Boot 2.6.0 开始,循环依赖默认被禁用。如果存在循环依赖关系,应用启动时将报错:

BeanCurrentlyInCreationException: Error creating bean with name 'beanA': Requested bean is currently in creation: Is there an unresolvable circular reference?

如何应对循环依赖???

解决方案1:重新设计依赖关系

最佳实践是避免循环依赖,重新设计 Bean 之间的依赖关系,确保不存在循环引用。这是最根本的解决之道。

// 修改前
@Component
public class BeanA {
    @Autowired
    private BeanB beanB;
}

@Component
public class BeanB {
    @Autowired
    private BeanA beanA;
}

// 修改后
@Component
public class BeanA {
    private final BeanB beanB;

    @Autowired
    public BeanA(BeanB beanB) {
        this.beanB = beanB;
    }
}

@Component
public class BeanB {
    private final BeanA beanA;

    @Autowired
    public BeanB(@Lazy BeanA beanA) {
        this.beanA = beanA;
    }
}

通过使用 @Lazy 延迟初始化,可以打破循环依赖。

解决方案2:启用循环依赖支持(不推荐)

如果确实无法避免循环依赖关系,可以选择启用循环依赖支持(仅建议在特殊情况下使用)。

在 application.properties 中添加以下配置:

spring.main.allow-circular-references=true

代码示例与解析

以下是一个完整代码示例,展示如何处理 Spring Boot 2.6.0 默认禁用循环依赖的情况。

示例1:重新设计依赖关系

修改前:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class BeanA {

    @Autowired
    private BeanB beanB;
}

@Component
public class BeanB {

    @Autowired
    private BeanA beanA;
}

修改后:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class BeanA {

    private final BeanB beanB;

    @Autowired
    public BeanA(BeanB beanB) {
        this.beanB = beanB;
    }
}

@Component
public class BeanB {

    private final BeanA beanA;

    @Autowired
    public BeanB(@Lazy BeanA beanA) {
        this.beanA = beanA;
    }
}

示例2:启用循环依赖支持

application.properties:

spring.main.allow-circular-references=true

源码解析

  • 在 Spring Boot 2.6.0 以前,Spring 通过三级缓存机制解决循环依赖问题。
  • 三级缓存机制中,一级缓存存放完全初始化好的 Bean,二级缓存存放提前曝光的 Bean,三级缓存存放 Bean 工厂。
  • 从 Spring Boot 2.6.0 起,默认禁用了循环依赖,旨在鼓励开发者通过合理设计避免循环依赖问题。

总结

Spring Boot 2.6.0 禁用循环依赖的变更是为了提升应用的健壮性和代码质量。通过重新设计依赖关系或在特殊情况下启用循环依赖支持,我们可以有效地应对这一变更。掌握这些知识和技巧,让你的 Spring Boot 项目更加稳定和高效!

不断学习,拥抱变化,让代码更优秀!

坚持学习,每天进步一点点!

分享知识,共同成长!祝你开发顺利!

#头条创作挑战赛##程序员##中方回应没邀请美方参与研究月壤#

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表