spring中bean的循环依赖及解决方案

Spring循环依赖指的是在Spring应用程序中,两个或多个Bean之间相互依赖,导致一个Bean的创建依赖于另一个Bean的创建,而后者又依赖于前者,从而形成一个循环依赖。通常,这种依赖关系会导致Bean的创建失败。

例如,假设有两个类 AB,它们彼此依赖:

public class A {
    private B b;

    public A(B b) {
        this.b = b;
    }
}

public class B {
    private A a;

    public B(A a) {
        this.a = a;
    }
}

在这种情况下,Spring无法初始化这两个Bean,因为A依赖于B的实例化,而B依赖于A的实例化,形成了一个循环依赖。

解决方法

在Spring框架中,三级缓存(three-level cache)是一种用于解决单例Bean循环依赖问题的机制。具体来说,三级缓存分为以下三个层次:

  1. 一级缓存(Singleton Objects):用于存储完全初始化的单例Bean。
  2. 二级缓存(Early Singleton Objects):用于存储部分初始化的Bean,主要是那些已经实例化但还没有完成所有依赖注入的Bean。
  3. 三级缓存(Singleton Factories):用于存储对象工厂,这些工厂可以在需要时创建Bean实例的代理对象,通常是为了解决循环依赖问题。
步骤详解
  1. 创建A的实例

    • Spring首先尝试创建Bean A 的实例。此时,A 的构造方法会被调用,但依赖的 B 还没有被注入。
  2. 将A的实例放入三级缓存

    • Spring将 A 的实例放入三级缓存中。三级缓存保存的是一个工厂,可以生成 A 的代理对象或是完成依赖注入的 A 实例。
  3. 创建B的实例

    • 在创建 B 的实例时,Spring发现 B 依赖于 A。此时 A 还没有完全初始化,但已经有了一个 A 的实例在三级缓存中。
  4. 从三级缓存获取A的实例

    • Spring通过三级缓存中的工厂获取 A 的实例,完成对 B 的依赖注入。此时,A 的实例可能是一个未完全初始化的代理对象,但可以暂时满足 B 的依赖。
  5. 完成B的初始化

    • 完成 B 的所有依赖注入和初始化,将 B 的实例放入一级缓存。
  6. 完成A的初始化

    • 回到 A 的初始化过程,现在 B 已经完全初始化,可以将 B 注入到 A 中。然后将 A 从三级缓存移到一级缓存。

三级缓存的具体作用

  • 一级缓存:存储完全初始化的Bean,避免重复初始化。
  • 二级缓存:存储部分初始化的Bean,防止多次实例化同一个Bean(但不解决循环依赖)。
  • 三级缓存:通过工厂模式,允许在初始化过程中获取未完全初始化的Bean,打破循环依赖。

代码示例(简化版)

class SingletonFactory {
    private final ObjectFactory<?> factory;

    public SingletonFactory(ObjectFactory<?> factory) {
        this.factory = factory;
    }

    public Object getObject() {
        return this.factory.getObject();
    }
}

public class CustomBeanFactory {
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    private final Map<String, SingletonFactory> singletonFactories = new ConcurrentHashMap<>();

    public Object getBean(String beanName) {
        Object singleton = this.singletonObjects.get(beanName);
        if (singleton == null) {
            singleton = this.earlySingletonObjects.get(beanName);
            if (singleton == null) {
                SingletonFactory factory = this.singletonFactories.get(beanName);
                if (factory != null) {
                    singleton = factory.getObject();
                    this.earlySingletonObjects.put(beanName, singleton);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
        return singleton;
    }

    public void registerBean(String beanName, ObjectFactory<?> factory) {
        this.singletonFactories.put(beanName, new SingletonFactory(factory));
    }

    public void addSingleton(String beanName, Object singleton) {
        this.singletonObjects.put(beanName, singleton);
        this.earlySingletonObjects.remove(beanName);
        this.singletonFactories.remove(beanName);
    }
}

通过这种机制,Spring能够有效地解决Bean的循环依赖问题,确保所有Bean都能正确地初始化和注入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值