开发者

springboot循环依赖问题案例代码及解决办法

目录
  • 1. 什么是循环依赖?
  • 2. 循环依赖的场景案例
  • 3. 解决循环依赖的常见方法
    • 方法 1:使用 @Lazy 注解
    • 方法 2:使用构造器注入解决循环依赖
    • 方法 3:使用 @PostConstruct 或 Setter 注入
    • 方法 4:使用 ObjectFactory 或 Provider 进行延迟注入
    • 方法 5:使用 @DependsOn 明确加载顺序
  • 4. 总结

    在 Spring Boot 中,如果两个或多个 Bean 之间存在循环依赖(即 Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A),会导致 Spring 的依赖注入机制无法正确处理,从而抛出异常。以下是循环依赖的场景分析、案例代码及常见的解决方法。

    1. 什么是循环依赖?

    概念

    循环依赖是指两个或多个 Bean 相互依赖,形成一个闭环。例如:

    • 直接python循环依赖
      • A 依赖 BB 依赖 A
    • 间接循环依赖
      • A 依赖 BB 依赖 C,而 C 又依赖 A

    2. 循环依赖的场景案例

    以下是一个简单的直接循环依赖场景。

    案例代码 Bean A

    @Component
    public class BeanA {
        @Autowired
        private BeanB beanB;
        public BeanA() {
            System.out.println("BeanA Constructor");
        }
        public void DOSomething() {
            System.out.println("BeanA is doing something");
        }
    }

    Bean B

    @Component
    public class BeanB {
        @Autowired
        private BeanA beanA;
        public BeanB() {
            System.out.println("BeanB Constructor");
        }
        public void doSomething() {
            System.out.println("BeanB is doing something");
        }
    }

    启动类

    @SpringBootApplication
    public class CircularDependencyDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(CircularDependencyDemoApplication.class, args);
        }
    }

    运行结果

    运行时,Spring 会抛出以下异常:

    Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:

    Error creating bean with name 'beanA':

    Requested bean is currently in creation: Is there an unresolvable circular reference?

    3. 解决循环依赖的常见方法

    方法 1:使用 @Lazy 注解

    @Lazy 注解可以延迟加载 Bean,使 Spring 在真正需要使用时才注入依赖,从而打破循环依赖。

    修改代码

    在其中一个依赖上添加 @Lazy 注解:

    BeanA:

    @Component
    public class BeanA {
        @Autowired
        @Lazy
        private BeanB beanB;
        public BeanA() {
            System.out.println("BeanA Constructor");
        }
        public void doSomething() {
            System.out.println("BeanA is doing something");
        }
    }

    BeanB:

    @Component
    public class BeanB {
        @Autowired
        private BeanA beaLWxNHiRIInA;
        public BeanB() {
            System.out.println("BeanB Constructor");
        }
        public void doSomething() {
            System.out.println("BeanB is doing something");
        }
    }

    运行结果

    程序运行正常,输出:

    BeanA Constructor

    BeanB Constructor

    方法 2:使用构造器注入解决循环依赖

    Spring 无法通过构造器注入解决循环依赖,因为在构造器注入的过程中,所有依赖必须在实例化时完全注入。这种情况下,需要重新设计代码结构以打破循环依赖。

    重构代码

    将循环依赖重构为单向依赖。例如,可以引入第三方协作者 Bean 来解耦。

    BeanA:

    @Component
    public class BeanA {
        private final Helper helper;
        public BeanA(Helper helper) {
            this.helper = helper;
            System.out.println("BeanA Constructor");
        }
        public void doSomething() {
            System.out.println("BeanA is doing something");
        }
    }

    BeanB:

    @Component
    public class BeanB {
        private final Helper helper;
        public BeanB(Helper helper) {
            this.helper = helper;
            System.out.println("BeanB Constructor");
        }
        public void doSomething() {
            System.out.println("BeanB is doing something");
        }
    }

    Helper:

    @Component
    public class Helper {
        public void assist() {
            System.out.println("Helper is assisting");
        }
    }

    运行结果

    Helper Constructor

    BeanA Constructor

    BeanB Constructor

    通过引入 HelperBeanABeanB 不再直接依赖彼此,循环依赖被消除。

    方法 3:使用 @PostConstruct 或 Setter 注入

    通过构造器注入会导致循环依赖问题,但可以使用 Setter 方法注入来延迟依赖注入的时机。

    修改代码

    BeanA:

    @Component
    public class BeanA {
        private BeanB beanB;
        public BeanA() {
            System.out.println("BeanA Constructor");
        }
        @Autowired
        public void setBeanB(BeanB beanB) {
            this.beanB = beanB;
        }
        public void doSomething() {
            System.out.println("BeanA is doing something");
        }
    }

    BeanB:

    @Component
    public class BeanB {
        private BeanA beanA;
        public BeanB() {
            System.out.println("BeanB Constructor");
        }
        @Autandroidowired
        public void setBeanA(BeanA beanA) {
            this.beanA = beanA;
        }
        public void doSomething() {
            System.out.println("BeanB is doing something");
        }
    }

    运行结果

    BeanA Constructor

    BeanB Constructor

    Setter 注入允许 Spring 在实例化 Bean 后再设置依赖,从而避免循环依赖问题。

    方法 4:使用 ObjectFactory 或 Provider 进行延迟注入

    Spring 提供了 ObjectFactoryProvider 接口,用于延迟获取 Bean,从而避免循环依赖。

    修改代码 BeanA:

    @Component
    public class BeanA {
        private final ObjectFactory<BeanB> beanBFactory;
        public BeanA(ObjectFactory<BeanB> beanBFactory) php{
            this.beanBFactory = beanBFactory;
            System.out.println("BeanA Constructor");
        }
        public void doSomething() {
            BeanB beanB = beanBFactory.getObject();
            System.out.println("BeanA is doing something with " + beanB);
        }
    }

    BeanB:

    @Component
    public class BeanB {
        private final BeanA beanA;
        @Autowired
        public BeanB(BeanA beanA) {
            this.beanA = beanA;
            System.out.println("BeanB Constructor");
        }
        public void doSomething() {
            System.out.println("BeanB is doing something");
        }
    }

    运行结果

    BeanA Constructor

    BeanB Constructor

    通过 ObjectFactory,BeanA 可以在需要时动态获取 BeanB,避免了循环依赖。

    方法 5:使用 @DependsOn 明确加载顺序

    如果循环依赖是因为 Bean 的加载顺序问题,可以使用 @DependsOn 指定加载顺序。

    修改代码

    BeanA:

    @Component
    @DependsOn("beanB") // 指定 BeanB 应该先加载
    public class BeanA {
        @Autowired
        private BeanB beanB;
        public BeanA() {
            System.out.println("BeanA Constructor");
        }
        public void doSomething() {
            System.out.println("BeanA is doing something");
        }
    }

    BeanB:

    @Component
    public class BeanB {
        @Autowired
        private BeanA beanA;python
        public BeanB() {
            System.out.println("BeanB Constructor");
        }
        public void doSomething() {
            System.out.println("BeanB is doing something");
        }
    }

    运行结果

    BeanB Constructor

    BeanA Constructor

    4. 总结

    循环依赖是常见问题,但可以通过多种方式解决:

    • 使用 @Lazy 延迟加载。
    • 重构代码,避免直接循环依赖。
    • 使用 Setter 注入或 @PostConstruct
    • 使用 ObjectFactory 或 Provider 进行延迟注入。
    • 使用 @DependsOn 明确加载顺序。

    推荐方案

    如果可以重构代码,消除循环依赖本身是最佳实践。在必要时,结合 @LazyObjectFactory 来解决循环依赖问题。

    到此这篇关于springboot循环依赖问题及其解决办法的文章就介绍到这了,更多相关springboot循环依赖内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜