spring解决循环依赖的方案

简介: spring解决循环依赖的方案

问题描述

当ServiceA和ServiceB相互依赖的时候,就会出现循环依赖的问题,循环依赖的代码可能如下:

@Component
public class A {
    // A中注入了B
    @Autowired
    private B b;
}
@Component
public class B {
    // B中也注入了A
    @Autowired
    private A a;
}

在启动服务的时候会报错。

问题分析

解决循环依赖的思路有两种,一种是在相互依赖的bean中新增中间状态,在一方依赖另一方的时候先给其一个中间状态的引用,待依赖双方创建完成后,再进行初始化,这个是spring解决循环依赖的思路。

另一种是在一个依赖的bean创建成功之后,再创建另一个bean,或者再手动触发另一个bean的依赖注入。这个是手动解决依赖注入的思路。

解决方案

方案一:

使用属性注入或setter注入方式。这种方式spring框架解决了注入依赖的问题。

@Component
public class Service1 {
    @Autowired
    private Service2 service2;
}
@Component
public class Service1 {
    private Service2 service2;
    @Autowired
    public Service1(Service2 service2) {
        this.service2 = service2;
    }
}

在springboot中使用以上方法解决注入依赖,还是会报依赖注入的错误,需要在配置文件application.properties中添加配置项:spring.main.allow-circular-references=true

方案二:

使用@Lazy。使用Bean的懒加载方式,在bean需要的时候才初始化它,这样规避了启动context的时候对有依赖关系的bean进行初始化从而报错的问题。

@Component
public class Service1 {
    private Service2 service2;
    @Autowired
    public void setService2(@Lazy Service2 service2) {
        this.service2 = service2;
    }
}

方案三:

使用@PostConstruct注解,在一个bean初始化后再初始化另一个。

@Component
public class CircularDependencyA {
    @Autowired
    private CircularDependencyB circB;
    @PostConstruct
    public void init() {
        circB.setCircA(this);
    }
    public CircularDependencyB getCircB() {
        return circB;
    }
}

方案四:

实现InitializingBean。该接口可以实现在bean初始化前后再进行操作的功能,通过实现ApplicationContextAware接口。

@Component
public class CircularDependencyA implements ApplicationContextAware, InitializingBean {
    private CircularDependencyB circB;
    private ApplicationContext context;
    public CircularDependencyB getCircB() {
        return circB;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        circB = context.getBean(CircularDependencyB.class);
    }
    @Override
    public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
        context = ctx;
    }
} 

问题总结

以上的解决循环依赖的方案都是存在循序依赖后才介入解决,其实最好的思路应该是不要再代码中存在循序依赖的逻辑,这样的逻辑本身可能就不合理


目录
相关文章
|
4天前
|
缓存 架构师 Java
图解 Spring 循环依赖,一文吃透!
Spring 循环依赖如何解决,是大厂面试高频,本文详细解析,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
图解 Spring 循环依赖,一文吃透!
|
12天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
2月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
189 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
1月前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
31 1
|
2月前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
40 4
|
2月前
|
前端开发 Java Spring
【非降版本解决】高版本Spring boot Swagger 报错解决方案
【非降版本解决】高版本Spring boot Swagger 报错解决方案
|
1月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
37 0
|
3月前
|
存储 缓存 Java
面试问Spring循环依赖?今天通过代码调试让你记住
该文章讨论了Spring框架中循环依赖的概念,并通过代码示例帮助读者理解这一概念。
面试问Spring循环依赖?今天通过代码调试让你记住
|
3月前
|
缓存 Java Spring
spring如何解决循环依赖
Spring框架处理循环依赖分为构造器循环依赖与setter循环依赖两种情况。构造器循环依赖不可解决,Spring会在检测到此类依赖时抛出`BeanCurrentlyInCreationException`异常。setter循环依赖则通过缓存机制解决:利用三级缓存系统,其中一级缓存`singletonObjects`存放已完成的单例Bean;二级缓存`earlySingletonObjects`存放实例化但未完成属性注入的Bean;三级缓存`singletonFactories`存放创建这些半成品Bean的工厂。
|
3月前
|
Java Spring 容器
循环依赖难破解?Spring Boot神秘武器@RequiredArgsConstructor与@Lazy大显神通!
【8月更文挑战第29天】在Spring Boot应用中,循环依赖是一个常见问题。当两个或多个Bean相互依赖形成闭环时,Spring容器会陷入死循环。本文通过对比@RequiredArgsConstructor和@Lazy注解,探讨它们如何解决循环依赖问题。**@RequiredArgsConstructor**:通过Lombok生成包含final字段的构造函数,优先通过构造函数注入依赖,简化代码但可能导致构造函数复杂。**@Lazy**:延迟Bean的初始化,直到首次使用,打破创建顺序依赖,增加灵活性但可能影响性能。根据具体场景选择合适方案可有效解决循环依赖问题。
119 0