暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring 中的循环依赖

程序员舒克 2022-01-04
328

01

什么是循环依赖

循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如ClassA引用ClassB,ClassB引用ClassA,则它们最终反映为一个环。如下图!

02
有哪几种循依赖

Spring容器循环依赖包括构造器循环依赖setter循环依赖

构造器循环依赖(代码如下)_________
定义《01:什么是循环依赖》里所说的两个类
// 定义ClassA类
public class ClassA {


private ClassB classB;


public ClassA(ClassB classB) {
this.classB = classB;
}
}

//定义ClassB类
public class ClassB {


private ClassA classA;


public ClassB(ClassA classA) {
this.classA = classA;
}
}
将ClassA、ClassB注入到Spring容器中(代码如下)
@Configuration
public class Config {


@Bean
public ClassA classA(ClassB classB){
return new ClassA(classB);
}


@Bean
public ClassB classB(ClassA classA){
return new ClassB(classA);
}
}


测试、看控制台报错提醒

public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
}
}
注:AnnotationConfigApplicationContext 用来读取配置类信息,读取到配置之后,就可以从Spring容器中获取我们注入的bean。当然,在平时写业务时,我们都习惯了用Junit测试类,测试Service或者Mapper等方法,如果bean是通过配置类注入的,或者通过xml注入的,也可以尝试用main方法测试,根据各自喜好,总之好几种方法都可以实现(题外话,扯远了)
查看控制台日志

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'classA': Requested bean is currently in creation: Is there an unresolvable circular reference?


  • 创建名为“classA”的 bean 时出错:当前正在创建请求的 bean:是否存在无法解析的循环引用?


构造器循环依赖之  解决方案
网上的帖子千篇一律,基本都说不能解决,但我翻阅了一些资料,竟让我找到了线索,来~跟牛哥一起揭开它神秘的面纱。
关键:打破循环的一种简单方法是说 Spring 懒惰地初始化其中一个 bean。也就是说:它不会完全初始化 bean,而是创建一个代理以将其注入另一个 bean。注入的 bean 只有在第一次需要时才会完全创建。
要想完成此操作,必须对配置类(Config.class)进行以下更改:
@Configuration
public class Config {


@Bean
public ClassA classA(@Lazy ClassB classB) {
return new ClassA(classB);
}


@Bean
public ClassB classB(ClassA classA) {
return new ClassB(classA);
}
}
如果你现在运行测试,你将看到这次错误不会发生。

Setter循环依赖_________

最流行的解决方法之一,也是Spring 文档提出的,是使用 setter 注入。

简单地说,如果你更改 bean 的连接方式以使用 setter 注入(或字段注入)而不是构造函数注入 - 这确实解决了问题。通过这种方式,Spring 创建了 bean,但在需要它们之前不会注入依赖项。(将ClassA、ClassB改成Setter方式,代码如下)

public class ClassA {


private ClassB classB;


@Autowired
public void setClassB(ClassB classB) {
this.classB = classB;
}


public ClassB getClassB() {
return classB;
}
}




public class ClassB {


private ClassA classA;


private String message = "Hi!";


@Autowired
public void setClassA(ClassA classA) {
this.classA = classA;
}


public String getMessage() {
return message;
}
}

配置类稍作修改:


@Configuration
public class Config {


@Bean
public ClassA classA() {
return new ClassA();
}


@Bean
public ClassB classB() {
return new ClassB();
}
}
测试

public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
ClassA classA = applicationContext.getBean(ClassA.class);
Assert.assertEquals("Hi!",classA.getClassB().getMessage());
}
}

注:断言的目的是确认是否正确注入,检查其消息属性的值。Setter循环依赖并不会报错

到此构造器循环依赖和Setter循环依赖就讲完了,希望以后的你越来越优秀,越来越美丽,加油吧,新时代农民工!!!


文章转载自程序员舒克,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论