什么是循環依賴
當一個ClassA依賴於ClassB,然后ClassB又反過來依賴ClassA,這就形成了一個循環依賴:
ClassA -> ClassB -> ClassA
原創聲明
本文發布於掘金號【Happyjava】。Happy的掘金地址:https://juejin.im/user/5cc2895df265da03a630ddca,Happy的個人博客:(http://blog.happyjava.cn)[http://blog.happyjava.cn]。歡迎轉載,但須保留此段聲明。
Spring的循環依賴問題
當你使用構造注入依賴的時候,就有可能發生循環依賴然后報錯的問題。什么是構造注入呢?可以看如下代碼:
假設有ClassA和ClassB如下:
ClassA.java
@Data
@Component
public class ClassA {
private final ClassB classB;
public ClassA(ClassB classB) {
this.classB = classB;
}
}
ClassB.java
@Data
@Component
public class ClassB {
private final ClassA classA;
public ClassB(ClassA classA) {
this.classA = classA;
}
}
就是在類的構造方法里,把依賴注入,這就是所說的構造注入。
構造注入,也是Spring團隊推薦的Spring依賴注入的方式(依賴來自IDEA的提示):
雖然是Spring的官方推薦,但是這種方式就是容易出現循環依賴導致程序跑不起來的情況:
當然,也存在多種解決循環依賴的辦法,下面一一演示。
重新設計代碼
當出現循環依賴的時候,可以考慮重新設計下代碼。一般來說,當循環依賴問題出現的時候,往往其原因是設計上分層沒有處理好,各個類的耦合度高,各自的職責不夠單一。
當然,很多時候,我們也沒有那么多時間去重新設計代碼。那么,我們可以采取別的方式。
使用懶加載
可以通過Spring提供的@Lazy注解,讓Spring懶加載,即當真正需要使用到該bean的時候,再去加載。如,我給上面的示例代碼的ClassB的構造方法加入@Lazy注解:
@Data
@Component
public class ClassB {
private final ClassA classA;
public ClassB(@Lazy ClassA classA) {
this.classA = classA;
}
}
再次啟動,就會發現循環依賴報錯問題不存在了。
直接使用Autowired單獨注入
直接使用@Autowired注入依賴,不要使用構造器的方式注入
@Data
@Component
public class ClassB {
@Autowired
private ClassA classA;
}
@Data
@Component
public class ClassA {
@Autowired
private ClassB classB;
}
這種方式,也可以解決Spring循環依賴的問題。
使用Setter注入
除了以上兩種方式,還可以通過setter的方式來注入依賴。如下:
ClassA.class
@Data
@Component
public class ClassA {
private ClassB classB;
@Autowired
public void setClassB(ClassB classB) {
this.classB = classB;
}
}
ClassB.class
@Data
@Component
public class ClassB {
private ClassA classA;
@Autowired
public void setClassA(ClassA classA) {
this.classA = classA;
}
}
通過Setter注入依賴的方式,一樣可以解決Spring循環依賴的問題。
總結
使用Spring作為開發框架,一不小心就會碰到循環依賴,程序啟動不了的問題。如果真的出現了循環依賴的問題,可以嘗試采用上面的幾種方式解決。當然,解決的辦法還有很多,比如,還可以通過PostConstruct注解來解決(摘抄baeldung的博客):
方法可能有很多種,就不太深入探討了。
關注公眾號領資料
搜索公眾號【Happyjava】,回復【電子書】和【視頻】,即可獲取大量優質電子書和大數據、kafka、nginx、MySQL等視頻資料