1.爲何須要控制加載順序web
springboot
聽從約定大於配置的原則,極大程度的解決了配置繁瑣的問題。在此基礎上,又提供了spi機制,用spring.factories
能夠完成一個小組件的自動裝配功能。面試
在通常業務場景,可能你不大關心一個bean是如何被註冊進spring容器的。只須要把須要註冊進容器的bean聲明爲@Component
便可,spring會自動掃描到這個Bean完成初始化並加載到spring上下文容器。spring
而當你在項目啓動時須要提早作一個業務的初始化工做時,或者你正在開發某個中間件須要完成自動裝配時。你會聲明本身的Configuration類,可是可能你面對的是好幾個有互相依賴的Bean。若是不加以控制,這時候可能會報找不到依賴的錯誤。編程
可是你明明已經把相關的Bean都註冊進spring上下文了呀。這時候你須要經過一些手段來控制springboot中的bean加載順序。springboot
2.幾個誤區
在正式說如何控制加載順序以前,先說2個誤區。微信
在標註了@Configuration
的類中,寫在前面的@Bean必定會被先註冊app
這個不存在的,spring在之前xml的時代,也不存在寫在前面必定會被先加載的邏輯。由於xml不是漸進的加載,而是所有parse好,再進行依賴分析和註冊。到了springboot中,只是省去了xml被parse成spring內部對象的這一過程,可是加載方式並無大的改變。學習
利用@Order
這個標註能進行加載順序的控制測試
嚴格的說,不是全部的Bean均可以經過@Order
這個標註進行順序的控制。你把@Order
這個標註加在普通的方法上或者類上一點鳥用都沒有。spa
那@Order
能控制哪些bean的加載順序呢,咱們先看看官方的解釋:
{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 { } 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 { } declarations (influencing a runtime-determined dependency graph). } defines the sort order
最開始@Order
註解用於切面的優先級指定;在 4.0 以後對它的功能進行了加強,支持集合的注入時,指定集合中 bean 的順序,而且特別指出了,它對於但實例的 bean 之間的順序,沒有任何影響。
目前用的比較多的有如下3點:
控制AOP的類的加載順序,也就是被
@Aspect
標註的類控制
ApplicationListener
實現類的加載順序控制
CommandLineRunner
實現類的加載順序
3.如何控制
3.1@DependsOn
@DependsOn
註解能夠用來控制bean的建立順序,該註解用於聲明當前bean依賴於另一個bean。所依賴的bean會被容器確保在當前bean實例化以前被實例化。
示例:
public class BeanOrderConfiguration {
public BeanA beanA(){ System.out.println("bean A init"); return new BeanA(); }
public BeanB beanB(){ System.out.println("bean B init"); return new BeanB(); }
public BeanC beanC(){ System.out.println("bean C init"); return new BeanC(); }
public BeanD beanD(){ System.out.println("bean D init"); return new BeanD(); }
public BeanE beanE(){ System.out.println("bean E init"); return new BeanE(); }}
以上代碼bean的加載順序爲:
bean B initbean A initbean E initbean D initbean C init
@DependsOn
的使用:
直接或者間接標註在帶有
@Component
註解的類上面;直接或者間接標註在帶有
@Bean
註解的方法上面;使用
@DependsOn
註解到類層面僅僅在使用 component-scanning 方式時纔有效,若是帶有@DependsOn
註解的類經過XML方式使用,該註解會被忽略,<bean depends-on="..."/>
這種方式會生效。
3.2 參數注入
在@Bean
標註的方法上,若是你傳入了參數,springboot會自動會爲這個參數在spring上下文裏尋找這個類型的引用。並先初始化這個類的實例。
利用此特性,咱們也能夠控制bean的加載順序。
示例:
@Beanpublic BeanA beanA(BeanB demoB){ System.out.println("bean A init"); return new BeanA();}
@Beanpublic BeanB beanB(){ System.out.println("bean B init"); return new BeanB();}
以上結果,beanB先於beanA被初始化加載。
須要注意的是,springboot會按類型去尋找。若是這個類型有多個實例被註冊到spring上下文,那你就須要加上@Qualifier("Bean的名稱")
來指定
3.3 利用bean的生命週期中的擴展點
在spring體系中,從容器到Bean實例化&初始化都是有生命週期的,而且提供了不少的擴展點,容許你在這些步驟時進行邏輯的擴展。
這些可擴展點的加載順序由spring本身控制,大多數是沒法進行干預的。咱們能夠利用這一點,擴展spring的擴展點。在相應的擴展點加入本身的業務初始化代碼。歷來達到順序的控制。
具體關於spring容器中大部分的可擴展點的分析,以前已經寫了一篇文章詳細介紹了:《Springboot啓動擴展點超詳細總結,不再怕面試官問了》。
3.4 @AutoConfigureOrder
這個註解用來指定配置文件的加載順序。可是在實際測試中發現,如下這樣使用是不生效的:
public class BeanOrderConfiguration1 { public BeanA beanA(){ System.out.println("bean A init"); return new BeanA(); }}
public class BeanOrderConfiguration2 { public BeanB beanB(){ System.out.println("bean B init"); return new BeanB(); }}
不管你2個數字填多少,都不會改變其加載順序結果。
那這個@AutoConfigureOrder
究竟是如何使用的呢。
通過測試發現,@AutoConfigureOrder
只能改變外部依賴的@Configuration
的順序。如何理解是外部依賴呢。
能被你工程內部scan到的包,都是內部的Configuration,而spring引入外部的Configuration,都是經過spring特有的spi文件:spring.factories
換句話說,@AutoConfigureOrder
能改變spring.factories
中的@Configuration
的順序。
具體使用方式:
public class BeanOrderConfiguration1 { public BeanA beanA(){ System.out.println("bean A init"); return new BeanA(); }}
public class BeanOrderConfiguration2 { public BeanB beanB(){ System.out.println("bean B init"); return new BeanB(); }}
spring.factories
:
\ = com.example.demo.BeanOrderConfiguration1,\ com.example.demo.BeanOrderConfiguration2
4.總結
其實在工做中,我相信不少人碰到過複雜的依賴關係的bean加載,把這種不肯定性交給spring去作,還不如咱們本身去控制,這樣在閱讀代碼的時候 ,也能輕易看出bean之間的依賴前後順序。
END
我是武哥,最後給你們 免費分享我寫的 10 萬字 Spring Boot 學習筆記(帶完整目錄)以及對應的源碼 。這是我以前在 CSDN 開的一門課,因此筆記很是詳細完整,我準備將資料分享出來給你們免費學習,相信你們看完必定會有所收穫( 下面有下載方式 )。
能夠看出,我當時備課很是詳細,目錄很是完整,讀者能夠手把手跟着筆記,結合源代碼來學習。如今免費分享出來,有須要的讀者能夠下載學習,就在我公衆號回覆:筆記,就行。
若有文章對你有幫助,
在看和轉發是對我最大的支持!
關注Java開發寶典
天天學習技術乾貨
點贊是最大的支持
本文分享自微信公衆號 - 武哥聊編程(eson_15)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。