简介

说明

        本文用实例介绍如何解决Spring的循环依赖问题。

相关网址

Spring--循环依赖导致启动失败_IT利刃出鞘的博客-博客_springboot 配置循环依赖

公共代码

package com.example.controller;

import com.example.tmp.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
@Autowired
private A a;

@GetMapping("/test1")
public String test1() {
return a.getTest();
}
}

方案1. Feild注入单例(@AutoWired)

代码

package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

private String name = "Tony";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTest() {
return b.getAge().toString() + name;
}
}
package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

private Integer age = 20;

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

}

测试

启动不报错。

postman访问:​​http://localhost:8080/test1​

后端结果:不报错

postman结果: 20Tony

方案2. 构造器注入+@Lazy

延迟加载:在注入依赖时,先注入代理对象,当首次使用时再创建对象完成注入。

代码

package com.example.tmp;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class A {
private B b;

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

private String name = "Tony";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTest() {
return b.getAge().toString() + name;
}
}
package com.example.tmp;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
public class B {
private A a;

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

private Integer age = 20;

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

}

测试

启动不报错。

postman访问:​​http://localhost:8080/test1​

后端结果:不报错

postman结果: 20Tony

方案3. Setter/Field注入单例

代码

package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class A {
private B b;

private String name = "Tony";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTest() {
return b.getAge().toString() + name;
}

public B getB() {
return b;
}

@Autowired
public void setB(B b) {
this.b = b;
}
}
package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class B {
private A a;

private Integer age = 20;

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public A getA() {
return a;
}

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

测试 

启动不报错。

postman访问:​​http://localhost:8080/test1​

后端结果:不报错

postman结果: 20Tony

方案4. @PostConstruct

代码

package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

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

@PostConstruct
public void init() {
b.setA(this);
}

private String name = "Tony";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTest() {
return b.getAge().toString() + name;
}
}
package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

private Integer age = 20;

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

public A getA() {
return a;
}

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

测试 

启动不报错。

postman访问:​​http://localhost:8080/test1​

后端结果:不报错

postman结果: 20Tony

方案5. 实现ApplicationContextAware与InitializingBean

代码 

package com.example.tmp;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class A implements ApplicationContextAware, InitializingBean {
private B b;

private ApplicationContext context;

private String name = "Tony";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getTest() {
return b.getAge().toString() + name;
}

@Override
public void afterPropertiesSet() throws Exception {
this.b = context.getBean(B.class);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
package com.example.tmp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

private Integer age = 20;

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}
}

测试 

启动不报错。

postman访问:​​http://localhost:8080/test1​

后端结果:不报错

postman结果: 20Tony