前言
實(shí)際開發(fā)中消略,我們常常是基于模塊分工開發(fā)的艺演,也就是不同的人負(fù)責(zé)不同的模塊。最后合并代碼晓殊。這種方式適合多人協(xié)同伤提,每個(gè)人只關(guān)心自己的業(yè)務(wù)模塊實(shí)現(xiàn)(controller/model/service/mapper等),當(dāng)碰到需要其它模塊支持的功能時(shí)介汹,只需引入其它模塊的類即可調(diào)用其方法
循環(huán)依賴問(wèn)題
Bean A 依賴 B,Bean B 依賴 A這種情況下出現(xiàn)循環(huán)依賴嘹承。
Bean A → Bean B → Bean A
更復(fù)雜的間接依賴造成的循環(huán)依賴如下如庭。
Bean A → Bean B → Bean C → Bean D → Bean E → Bean A
循環(huán)依賴問(wèn)題的本質(zhì)
當(dāng)程序啟動(dòng),Spring Context加載所有的Bean時(shí)豪娜,會(huì)嘗試按他們運(yùn)行的工作順序創(chuàng)建Bean哟楷。
例如,有如下依賴:
Bean A → Bean B → Bean C
Spring先創(chuàng)建beanC卖擅,接著創(chuàng)建bean B(將C注入B中)惩阶,最后創(chuàng)建bean A(將B注入A中)。
但當(dāng)存在循環(huán)依賴時(shí)断楷,Spring將無(wú)法決定先創(chuàng)建哪個(gè)bean。這種情況下恐锣,Spring將產(chǎn)生異常BeanCurrentlyInCreationException。
舉例
有一個(gè)ServiceA需要調(diào)用ServiceB的方法土榴,那么ServiceA就依賴于ServiceB,那在ServiceB中再調(diào)用ServiceA的方法赫段,就形成了循環(huán)依賴矢赁。Spring在初始化bean的時(shí)候就不知道先初始化哪個(gè),bean就會(huì)報(bào)錯(cuò)坯台。
解決
重新設(shè)計(jì)
重新設(shè)計(jì)結(jié)構(gòu)瘫寝,消除循環(huán)依賴焕阿。使用注解 @Lazy
一種最簡(jiǎn)單的消除循環(huán)依賴的方式是通過(guò)延遲加載。在注入依賴時(shí)暮屡,先注入代理對(duì)象,當(dāng)首次使用時(shí)再創(chuàng)建對(duì)象完成注入准夷。
@Autowired
@Lazy
private ServiceA serviceA;
@Autowired
@Lazy
private ServiceB serviceB;
- 使用Setter/Field注入
Spring文檔建議的一種方式是使用setter注入莺掠。當(dāng)依賴最終被使用時(shí)才進(jìn)行注入。
@Component
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
public ServiceB getServiceB() {
return serviceB;
}
}
- 使用@PostConstruct
@Component
public class ServiceA {
@Autowired
private ServiceB serviceB;
@PostConstruct
public void init() {
serviceB.setServiceA(this);
}
public ServiceB getServiceB() {
return serviceB;
}
}