1. 程式人生 > >如果你還不知道如何控制springboot中bean的載入順序,那你一定要看此篇

如果你還不知道如何控制springboot中bean的載入順序,那你一定要看此篇

## 1.為什麼需要控制載入順序 `springboot`遵從約定大於配置的原則,極大程度的解決了配置繁瑣的問題。在此基礎上,又提供了spi機制,用`spring.factories`可以完成一個小元件的自動裝配功能。 在一般業務場景,可能你不大關心一個bean是如何被註冊進spring容器的。只需要把需要註冊進容器的bean宣告為`@Component`即可,spring會自動掃描到這個Bean完成初始化並載入到spring上下文容器。 而當你在專案啟動時需要提前做一個業務的初始化工作時,或者你正在開發某個中介軟體需要完成自動裝配時。你會宣告自己的Configuration類,但是可能你面對的是好幾個有互相依賴的Bean。如果不加以控制,這時候可能會報找不到依賴的錯誤。 但是你明明已經把相關的Bean都註冊進spring上下文了呀。這時候你需要通過一些手段來控制springboot中的bean載入順序。 ## 2.幾個誤區 在正式說如何控制載入順序之前,先說2個誤區。 *在標註了`@Configuration`的類中,寫在前面的@Bean一定會被先註冊* 這個不存在的,spring在以前xml的時代,也不存在寫在前面一定會被先載入的邏輯。因為xml不是漸進的載入,而是全部parse好,再進行依賴分析和註冊。到了springboot中,只是省去了xml被parse成spring內部物件的這一過程,但是載入方式並沒有大的改變。 *利用`@Order`這個標註能進行載入順序的控制* 嚴格的說,不是所有的Bean都可以通過`@Order`這個標註進行順序的控制。你把`@Order`這個標註加在普通的方法上或者類上一點鳥用都沒有。 那`@Order`能控制哪些bean的載入順序呢,我們先看看官方的解釋: > {@code @Order} defines the sort order for an annotated component. Since Spring 4.0, annotation-based ordering is supported for many kinds of components in Spring, even for collection injection where the order values of the target components are taken into account (either from their target class or from their {@code @Bean} method). While such order values may influence priorities at injection points, please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and {@code @DependsOn} declarations (influencing a runtime-determined dependency graph). 最開始`@Order`註解用於切面的優先順序指定;在 4.0 之後對它的功能進行了增強,支援集合的注入時,指定集合中 bean 的順序,並且特別指出了,它對於但例項的 bean 之間的順序,沒有任何影響。 目前用的比較多的有以下3點: * 控制AOP的類的載入順序,也就是被`@Aspect`標註的類 * 控制`ApplicationListener`實現類的載入順序 * 控制`CommandLineRunner`實現類的載入順序 ## 3.如何控制 ### 3.1@DependsOn `@DependsOn`註解可以用來控制bean的建立順序,該註解用於聲明當前bean依賴於另外一個bean。所依賴的bean會被容器確保在當前bean例項化之前被例項化。 示例: ```java @Configuration public class BeanOrderConfiguration { @Bean @DependsOn("beanB") public BeanA beanA(){ System.out.println("bean A init"); return new BeanA(); } @Bean public BeanB beanB(){ System.out.println("bean B init"); return new BeanB(); } @Bean @DependsOn({"beanD","beanE"}) public BeanC beanC(){ System.out.println("bean C init"); return new BeanC(); } @Bean @DependsOn("beanE") public BeanD beanD(){ System.out.println("bean D init"); return new BeanD(); } @Bean public BeanE beanE(){ System.out.println("bean E init"); return new BeanE(); } } ``` 以上程式碼bean的載入順序為: ``` bean B init bean A init bean E init bean D init bean C init ``` `@DependsOn`的使用: - 直接或者間接標註在帶有`@Component`註解的類上面; - 直接或者間接標註在帶有`@Bean`註解的方法上面; - 使用`@DependsOn`註解到類層面僅僅在使用 component-scanning 方式時才有效,如果帶有`@DependsOn`註解的類通過XML方式使用,該註解會被