前言
實際開發中,咱們經常是基於模塊分工開發的,也就是不一樣的人負責不一樣的模塊。最後合併代碼。這種方式適合多人協同,每一個人只關心本身的業務模塊實現(controller/model/service/mapper等),當碰到須要其它模塊支持的功能時,只需引入其它模塊的類便可調用其方法html
循環依賴問題
Bean A 依賴 B,Bean B 依賴 A這種狀況下出現循環依賴。
Bean A → Bean B → Bean Aapp
更復雜的間接依賴形成的循環依賴以下。
Bean A → Bean B → Bean C → Bean D → Bean E → Bean Athis
循環依賴問題的本質
當程序啓動,Spring Context加載全部的Bean時,會嘗試按他們運行的工做順序建立Bean。.net
例如,有以下依賴:
Bean A → Bean B → Bean C
Spring先建立beanC,接着建立bean B(將C注入B中),最後建立bean A(將B注入A中)。設計
但當存在循環依賴時,Spring將沒法決定先建立哪一個bean。這種狀況下,Spring將產生異常BeanCurrentlyInCreationException。代理
舉例
有一個ServiceA須要調用ServiceB的方法,那麼ServiceA就依賴於ServiceB,那在ServiceB中再調用ServiceA的方法,就造成了循環依賴。Spring在初始化bean的時候就不知道先初始化哪一個,bean就會報錯。code
解決
從新設計
從新設計結構,消除循環依賴。htm
使用註解 @Lazy
一種最簡單的消除循環依賴的方式是經過延遲加載。在注入依賴時,先注入代理對象,當首次使用時再建立對象完成注入。
對象
@Autowired @Lazy private ServiceA serviceA; @Autowired @Lazy private ServiceB serviceB;
使用Setter/Field注入
Spring文檔建議的一種方式是使用setter注入。當依賴最終被使用時才進行注入。blog
@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; } }