Spring中@order註解用法實戰教程
前言
@order
註解是spring-core
包下的一個註解,@Order
的作用是定義Spring IOC容器中Bean的執行順序的優先級(這裡的順序也可以理解為存放到容器中的先後順序)。開發過程當中有時候經常會出現配置依賴關系,例如註入A對象使用瞭
@ConditionalOnBean(B.class)
,意思是要求容器當中必須存在B.class
的實例的時候,才會進行註入A
。這時候我們就必須保證B對象在註入A
對象前進行註入。
一、觀察@order源碼
(1)源碼當中有三個元註解:
- @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}): 使用范圍接口、類、枚舉、註解、方法、字段
- @Retention(RetentionPolicy.RUNTIME): @Retention是用來修飾註解的生命周期的,RetentionPolicy.RUNTIME代表的是不僅被保存到class文件中,jvm加載class文件之後,仍然存在;一直有效!
- @Documented: @Documented和@Deprecated註解長得有點像,@Deprecated是用來標註某個類或者方法不建議再繼續使用,@Documented隻能用在註解上,如果一個註解@B,被@Documented標註,那麼被@B修飾的類,生成Javadoc文檔時,會顯示@B。
(2)屬性:
@order當中隻要一個value屬性,而且還是int類型,值越低優先級越高,默認值是Ordered.LOWEST_PRECEDENCE
,表示最低優先級(輸給任何其他指定的順序值)。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @interface Order { int value() default 2147483647; }
官網註釋:https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/annotation/Order.java
二、@order實戰
(1)自定義兩個配置類
我們要求Config2先進行加載,然後通過@order來排序測試一下
@Configuration public class Config1 { public Config1() { System.out.println("Config1構建瞭"); } } @Configuration public class Config2 { public Config2() { System.out.println("Config2構建瞭"); } }
(2)啟動項目測試:默認是先創建的Config1後創建的Config2
(3)既然order可以控制加載順序,那我們來試驗一下,然後讓Config2 先加載
@Configuration @Order(2) public class Config1 { public Config1() { System.out.println("Config1構建瞭"); } } @Configuration @Order(1) public class Config2 { public Config2() { System.out.println("Config2構建瞭"); } }
但是好像沒什麼卵用
(4)分析原因
目前這兩個是在同包情況下不起作用。
於是進行分開瞭
分開之後竟然生效瞭
(5)但是分開也是將Config2放到瞭上面的包當中,於是我又改成瞭Config1放到最上面,這樣進行測試,結果又失效瞭
(6)於是我又放在瞭同包下,將Config2命名為A開頭的,這樣他就放到瞭最上面,於是這樣同樣也生效瞭。
期間我還嘗試著將@Configuration都改為使用@Component,結果仍然不變。
得出結論:
@order
指定加載順序還跟類的命名和存放位置有關!假如有Config1
和Config2
兩個類在一個包下,要求是Config2
先加載:
- 這時候設置
Config2
的@order值
就算是小於Config1
的@order值
同樣也是Config1
先加載。 - 如果同包情況下可以重新命名Config2,隻要在Config1上面就行。
- 或者拆開不同包也可以,但是Config2所在的包也必須比Config1所呆的包上面。
這樣才能保證@Order生效!
三、@order失效原因
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-constructor-injection
最關鍵的一句話:您可以在目標類級別和@Bean方法上聲明@Order註釋,可能針對的是單個bean定義(如果多個定義使用同一個bean類)。@Order值可能會影響註入點的優先級,但請註意,它們不會影響單例啟動順序,這是由依賴關系和@DependsOn聲明確定的正交關註。
我理解的註入點的優先級應該是指的存放容器的先後順序,也就是他並不會影響啟動順序。
四、解決排序問題
我們不可能每次遇到這種問題又是改名又是換包的,所以,springboot提供瞭如下三個註解可以控制順序:
- @AutoConfigureAfter:當前配置類在指定配置類之後執行
- @AutoConfigureBefore:當前配置類在指定配置類之前執行
- @AutoConfigureOrder:指定優先級,數值越小,優先級越高。
(1)首先將代碼改回原來的樣子
(2)在Config2使用@AutoConfigureBefore(Config1.class),代表的是在config1加載前進行加載
@Configuration public class Config1 { public Config1() { System.out.println("Config1構建瞭"); } } @Configuration @AutoConfigureBefore(Config1.class) public class Config2 { public Config2() { System.out.println("Config2構建瞭"); } }
(3)輸出結果,顯然還是沒生效
可能有時候走瞭運給你一種錯覺還真的配置成功瞭。實際上這種方式是不可行的,以上三個註解隻有針對自動配置類才會生效。
在autoconfigure包下就有spring.factories,這個文件配置瞭自動配置類,springboot會讀取這個文件的,我們也可以在自己項目上定義spring.factories,這樣我們的配置類對於@AutoConfigureAfter註解就可以生效瞭。
(4)自定義spring.factories
第一行是固定的,後面的就是全類名,雖然隻有Config2使用瞭註解,但是需求是和Config1進行排序,所以這兩個都得加。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.gzl.cn.springbootcache.config.Config2,\ com.gzl.cn.springbootcache.config.Config1
(5)測試,成功解決
五、排序源碼分析
針對於@AutoConfigure那三個註解原理:其實關鍵的代碼還是在AutoConfigurationImportSelector中,將自動配置類從spring.factories加載出來之後會根據條件排序(隻有自動配置類!),在selectImports()方法中最後一行代碼如下:
緊接著會走到這個地方,實際上是分瞭三步排序:
- 先按照文件名字母排序
- 按照@AutoConfigureOrder進行排序
- 按照 @AutoConfigureBefore和@AutoConfigureAfter排序
從上面配置的順序可以知道,最終決定權還是在@AutoConfigureAfter、@AutoConfigureBefore這兩個註解。
當我們不設置spring.factories的時候,這裡面壓根都沒有這兩個類!
六、@AutoConfigureOrder
這種也是可以的!當然前提也是需要配置spring.factories
@Configuration @AutoConfigureOrder(2) public class Config1 { public Config1() { System.out.println("Config1構建瞭"); } } @Configuration @AutoConfigureOrder(1) public class Config2 { public Config2() { System.out.println("Config2構建瞭"); } }
總結
到此這篇關於Spring中@order註解用法的文章就介紹到這瞭,更多相關Spring @order註解用法內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Springboot @Configuration與自動配置詳解
- Java元註解Retention代碼示例介紹
- SpringBoot自動配置特點與原理詳細分析
- Spring @Import註解的使用
- SpringBoot底層註解超詳細介紹