1. 程式人生 > >Spring如何解決迴圈依賴?

Spring如何解決迴圈依賴?

![在這裡插入圖片描述](https://img2020.cnblogs.com/other/748509/202006/748509-20200622211636565-1098461573.jpg) ## 介紹 先說一下什麼是迴圈依賴,Spring在初始化A的時候需要注入B,而初始化B的時候需要注入A,在Spring啟動後這2個Bean都要被初始化完成 Spring的迴圈依賴有兩種場景 1. 構造器的迴圈依賴 2. 屬性的迴圈依賴 構造器的迴圈依賴,可以在建構函式中使用@Lazy註解延遲載入。在注入依賴時,先注入代理物件,當首次使用時再建立物件完成注入 屬性的迴圈依賴主要是通過3個map來解決的 ## 構造器的迴圈依賴 ```java @Component public class ConstructorA { private ConstructorB constructorB; @Autowired public ConstructorA(ConstructorB constructorB) { this.constructorB = constructorB; } } ``` ```java @Component public class ConstructorB { private ConstructorA constructorA; @Autowired public ConstructorB(ConstructorA constructorA) { this.constructorA = constructorA; } } ``` ```java @Configuration @ComponentScan("com.javashitang.dependency.constructor") public class ConstructorConfig { } ``` ```java public class ConstructorMain { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConstructorConfig.class); System.out.println(context.getBean(ConstructorA.class)); System.out.println(context.getBean(ConstructorB.class)); } } ``` 執行ConstructorMain的main方法的時候會在第一行就報異常,說明Spring沒辦法初始化所有的Bean,即上面這種形式的迴圈依賴Spring無法解決。 我們可以在ConstructorA或者ConstructorB建構函式的引數上加上@Lazy註解就可以解決 ```java @Autowired public ConstructorB(@Lazy ConstructorA constructorA) { this.constructorA = constructorA; } ``` 因為我們主要關注屬性的迴圈依賴,構造器的迴圈依賴就不做過多分析了 ## 屬性的迴圈依賴 先演示一下什麼是屬性的迴圈依賴 ```java @Component public class FieldA { @Autowired private FieldB fieldB; } ``` ```bash @Component public class FieldB { @Autowired private FieldA fieldA; } ``` ```java @Configuration @ComponentScan("com.javashitang.dependency.field") public class FieldConfig { } ``` ```java public class FieldMain { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FieldConfig.class); // com.javashitang.dependency.field.FieldA@3aa9e816 System.out.println(context.getBean(FieldA.class)); // com.javashitang.dependency.field.FieldB@17d99928 System.out.println(context.getBean(FieldB.class)); } } ``` Spring容器正常啟動,能獲取到FieldA和FieldB這2個Bean 屬性的迴圈依賴在面試中還是經常被問到的。總體來說也不復雜,但是涉及到Spring Bean的初始化過程,所以感覺比較複雜,我寫個demo演示一下整個過程 Spring的Bean的初始化過程其實比較複雜,為了方便理解Demo,我就把Spring Bean的初始化過程分為2部分 1. bean的例項化過程,即呼叫建構函式將物件創建出來 2. bean的初始化過程,即填充bean的各種屬性 bean初始化過程完畢,則bean就能被正常創建出來了 下面開始寫Demo,ObjectFactory介面用來生產Bean,和Spring中定義的介面一樣 ```java public interface Objec