Spring 循环依赖解析(上)

简介: Spring 现在其实是我们 Java 程序开发离不开的基础框架,个人觉得除了 JDK 我们用得最多的 Java 中间件就是 Spring ,今天我们一起来学习一下 Spring 的循环依赖。

常见问题


  • 你解释一下 spring 中的三级缓存?


  • 三级缓存分别是什么?三个 Map 有什么异同?


  • 什么是循环依赖?请谈谈?你看过 spring 的源码吗?一般我们说的是 spring  容器是什么?


  • 多例的情况下,循环依赖问题为什么无法解决?


什么是循环依赖?


多个 bean 之间相互依赖,形成闭环。 比如:A 依赖于 B, B 依赖于 C , C 依赖于 A示例代码


public class T1 {
  class A {
    B b;
  }
  class B {
    C c;
  }
  class C {
    A a; 
  }
}


比如:A 依赖于 B, B 依赖于 C , C 依赖于 A


通常来说,如果问 Spring 容器内部如何解决循环依赖,一定是指默认的单例 Bean 中, 属性相互引用的场景。


@Component
public class A {
    @Autowired
  private B b;
}
@Component
public class B {
    @Autowired
  private C c;
}
@Component
public class C {
    @Autowired
  private A a;
}


循环依赖说明


官方说明


参考官方说,下面会有官网链接


image.png


官网链接:docs.spring.io/spring-fram…


结论


构造方法注入:不支持循环依赖。结论:我们 AB 循环依赖问题。只要 A 的方式是 setter 且 singleton 就不会有循环依赖问题。


BeanCurrentlyInCreationException


循环依赖异常的定义如下所示,如果出现循环依赖,我们在启动/运行过程中会报这个错误。


image.png


依赖注入的两种方式


方式一:构造器方式注入依赖


@Component
public class ServiceA{
    private ServiceB serviceB;
    public ServiceA(ServiceB serverB) {
       this.serivceB = serviceB;
    }     
}
@Component
public class ServiceB{
    private ServiceA serviceA;
    public ServiceB(ServiceA serviceA) {
       this.serviceA = serviceA;
    }     
}


构造器循环依赖是无法解决的,你想让构造器注入支持循环依赖,是不可能的。


方式二:以 set 方式注入依赖


@Component
public class ServiceA{
    private ServiceB serviceB;
    public setServiceB(ServiceB serverB) {
       this.serivceB = serviceB;
    }     
}
@Component
public class ServiceB{
    private ServiceA serviceA;
    public setServiceB(ServiceA serviceA) {
       this.serviceA = serviceA;
    }     
}


案例演示(基于 Spring 容器的循环依赖)


普通的 Java 基础编码A  类、B 类


@Data
public class A{
  private B b;
  public A() {
     System.out.println("----- A create success");
  }
}
@Data
public class B{
  private a a;
  public B() {
     System.out.println("------ B create success");
  }    
}


循环依赖解决


A a = new A();
B b = new B();
a.setB(b);
b.setA(a);


基于 Spring 容器的循环依赖


  • 默认的单例(singleton)的场景是支持循环依赖的,不报错


  • 原型(prototype)的场景是不支持循环依赖的, 会报错


代码演示


  • 循环依赖代码


@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}


  • 默认单例,修改为原型


// 增加注解
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)


  • 一段测试程序


class BTest {
    @Configuration
    @Import({A.class, B.class})
    public static class TestConfig {
    }
    @Test
    public void currentlyincreation() {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(TestConfig.class);
        // 这里要获取 bean 一下,如果不去主动获取,可能是由于惰性加载没有执行,不会报错
        A a = applicationContext.getBean(A.class);
        System.out.println(a);
    }
}


  • 循环依赖异常


image.png


相关文章
|
5月前
|
数据采集 人工智能 Java
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
DevDocs是一款基于智能爬虫技术的开源工具,支持1-5层深度网站结构解析,能将技术文档处理时间从数周缩短至几小时,并提供Markdown/JSON格式输出与AI工具无缝集成。
189 1
1天消化完Spring全家桶文档!DevDocs:一键深度解析开发文档,自动发现子URL并建立图谱
|
5月前
|
安全 Java API
深入解析 Spring Security 配置中的 CSRF 启用与 requestMatchers 报错问题
本文深入解析了Spring Security配置中CSRF启用与`requestMatchers`报错的常见问题。针对CSRF,指出默认已启用,无需调用`enable()`,只需移除`disable()`即可恢复。对于`requestMatchers`多路径匹配报错,分析了Spring Security 6.x中方法签名的变化,并提供了三种解决方案:分次调用、自定义匹配器及降级使用`antMatchers()`。最后提醒开发者关注版本兼容性,确保升级平稳过渡。
608 2
|
6月前
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `<appender>` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `<logger>` 和 `<root>` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
1320 1
|
5月前
|
监控 安全 Java
解决 Spring Boot 中 SecurityConfig 循环依赖问题的详解
本文详细解析了在 Spring Boot 中配置 `SecurityConfig` 时可能遇到的循环依赖问题。通过分析错误日志与代码,指出问题根源在于 `SecurityConfig` 类中不当的依赖注入方式。文章提供了多种解决方案:移除 `configureGlobal` 方法、定义 `DaoAuthenticationProvider` Bean、使用构造函数注入以及分离配置类等。此外,还讨论了 `@Lazy` 注解和允许循环引用的临时手段,并强调重构以避免循环依赖的重要性。通过合理设计 Bean 依赖关系,可确保应用稳定启动并提升代码可维护性。
410 0
|
5月前
|
前端开发 安全 Java
Spring Boot 便利店销售系统项目分包设计解析
本文深入解析了基于Spring Boot的便利店销售系统分包设计,通过清晰的分层架构(表现层、业务逻辑层、数据访问层等)和模块化设计,提升了代码的可维护性、复用性和扩展性。具体分包结构包括`controller`、`service`、`repository`、`entity`、`dto`、`config`和`util`等模块,职责分明,便于团队协作与功能迭代。该设计为复杂企业级应用开发提供了实践参考。
196 0
|
3月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
133 1
|
2月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
|
2月前
|
SQL Java 数据库连接
Spring、SpringMVC 与 MyBatis 核心知识点解析
我梳理的这些内容,涵盖了 Spring、SpringMVC 和 MyBatis 的核心知识点。 在 Spring 中,我了解到 IOC 是控制反转,把对象控制权交容器;DI 是依赖注入,有三种实现方式。Bean 有五种作用域,单例 bean 的线程安全问题及自动装配方式也清晰了。事务基于数据库和 AOP,有失效场景和七种传播行为。AOP 是面向切面编程,动态代理有 JDK 和 CGLIB 两种。 SpringMVC 的 11 步执行流程我烂熟于心,还有那些常用注解的用法。 MyBatis 里,#{} 和 ${} 的区别很关键,获取主键、处理字段与属性名不匹配的方法也掌握了。多表查询、动态
|
4月前
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
|
3月前
|
Java 数据库 开发者
Spring Boot 框架超级详细总结及长尾关键词应用解析
本文深入讲解Spring Boot框架的核心概念、功能特性及实际应用,涵盖自动配置、独立运行、starter依赖等优势。通过Web开发、微服务架构、批处理等适用场景分析,结合在线书店实战案例,演示项目初始化、数据库设计、分层架构实现全流程。同时探讨热部署、多环境配置、缓存机制与事务管理等高级特性,助你高效掌握Spring Boot开发技巧。代码示例详尽,适合从入门到进阶的学习者。
862 0

推荐镜像

更多
  • DNS