spring的依赖循环

一、什么是依赖循环?

举个例子,两个或以上Bean,A需要B,B需要C,C需要A,于是形成了一个循环:尝试创建A-需要B-尝试创建B-需要C-尝试创建C-需要A-尝试创建A……以此往复。

在Spring中循环依赖一共可以分为两种情况:

1.构造器循环依赖。例如:

public class A {
    private B b;

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

public class B {
    private A a;

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

2.属性循环依赖,例如:

public class A {
  private B b;

  public void setB(B b) {
    this.b = b;
  }
}

public class B {
  private A a;

  public void setA(A a) {
    this.a = a;
  }

其中第二类又可以细分为,单例模式下的循环依赖和prototype即多例下的循环依赖,而三种情况中,spring仅提供了对单例模式下属性循环依赖的解决方法。

二、如何解决依赖循环

以两个类为例,A、B两个类相互依赖,初始化A的时候,第一步实例化A完成(生成对象工厂实例放入三级缓存),注入依赖属性B,一级缓存查询B没有,二级缓存查询B没有,

初始化B(生成对象工厂实例放入三级缓存),注入依赖属性A,一级缓存查询A没有,二级缓存查询A没有,三级缓存查询到A的对象工厂,需要AOP增强则生成A的代理对象,没有则直接创建A实例对象,并将A放入到二级缓存,注入A的代理对象完成,生成代理对象B,B移入一级缓存。

继续A属性注入(B的代理对象),然后可能还会依赖注入C对象流程和B一致,所有依赖注入完成后A初始化,生成A的代理对象,发现A的代理对象已存在,则跳过,放入一级缓存。此时A的代理对象也是提前生成的,但是仅针对循环依赖提前生成。

具体使用如下:

@Component
public class A {
    @Autowired
    private B b;

}

@Component
public class B {
    @Autowired
    private A a;

}

或:

@Component
public class A {
  private B b;

  @Autowired
  public void setB(B b) {
    this.b = b;
  }
}

@Component
public class B {
  private A a;

  @Autowired
  public void setA(A a) {
    this.a = a;
  }
}

因为spring的bean默认的就是单例模式,我们只要确保没有在构造器中形成循环依赖就可以解决大部分问题。

如果无法防止构造器中形成依赖循环,我们也可以通过@Lazy注解来解决,例如:

@Component
public class A {
    private B b;

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

@Component
public class B {
    private A a;

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

这样spring不会直接生成一个a或者b的对象,而是先给一个代理对象,当真正需要使用时,才真正使用代理对象来生成a或b的对象,以此解决构造器的循环依赖问题。

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值