Spring中@order注解用法實(shí)戰(zhàn)教程
前言
@order
注解是spring-core
包下的一個(gè)注解,@Order
的作用是定義Spring IOC容器中Bean的執(zhí)行順序的優(yōu)先級(jí)(這里的順序也可以理解為存放到容器中的先后順序)。開發(fā)過程當(dāng)中有時(shí)候經(jīng)常會(huì)出現(xiàn)配置依賴關(guān)系,例如注入A對(duì)象使用了
@ConditionalOnBean(B.class)
,意思是要求容器當(dāng)中必須存在B.class
的實(shí)例的時(shí)候,才會(huì)進(jìn)行注入A
。這時(shí)候我們就必須保證B對(duì)象在注入A
對(duì)象前進(jìn)行注入。
一、觀察@order源碼
(1)源碼當(dāng)中有三個(gè)元注解:
- @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}): 使用范圍接口、類、枚舉、注解、方法、字段
- @Retention(RetentionPolicy.RUNTIME): @Retention是用來修飾注解的生命周期的,RetentionPolicy.RUNTIME代表的是不僅被保存到class文件中,jvm加載class文件之后,仍然存在;一直有效!
- @Documented: @Documented和@Deprecated注解長(zhǎng)得有點(diǎn)像,@Deprecated是用來標(biāo)注某個(gè)類或者方法不建議再繼續(xù)使用,@Documented只能用在注解上,如果一個(gè)注解@B,被@Documented標(biāo)注,那么被@B修飾的類,生成Javadoc文檔時(shí),會(huì)顯示@B。
(2)屬性:
@order當(dāng)中只要一個(gè)value屬性,而且還是int類型,值越低優(yōu)先級(jí)越高,默認(rèn)值是Ordered.LOWEST_PRECEDENCE
,表示最低優(yōu)先級(jí)(輸給任何其他指定的順序值)。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @interface Order { int value() default 2147483647; }
官網(wǎng)注釋:https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/annotation/Order.java
二、@order實(shí)戰(zhàn)
(1)自定義兩個(gè)配置類
我們要求Config2先進(jìn)行加載,然后通過@order來排序測(cè)試一下
@Configuration public class Config1 { public Config1() { System.out.println("Config1構(gòu)建了"); } } @Configuration public class Config2 { public Config2() { System.out.println("Config2構(gòu)建了"); } }
(2)啟動(dòng)項(xiàng)目測(cè)試:默認(rèn)是先創(chuàng)建的Config1后創(chuàng)建的Config2
(3)既然order可以控制加載順序,那我們來試驗(yàn)一下,然后讓Config2 先加載
@Configuration @Order(2) public class Config1 { public Config1() { System.out.println("Config1構(gòu)建了"); } } @Configuration @Order(1) public class Config2 { public Config2() { System.out.println("Config2構(gòu)建了"); } }
但是好像沒什么卵用
(4)分析原因
目前這兩個(gè)是在同包情況下不起作用。
于是進(jìn)行分開了
分開之后竟然生效了
(5)但是分開也是將Config2放到了上面的包當(dāng)中,于是我又改成了Config1放到最上面,這樣進(jìn)行測(cè)試,結(jié)果又失效了
(6)于是我又放在了同包下,將Config2命名為A開頭的,這樣他就放到了最上面,于是這樣同樣也生效了。
期間我還嘗試著將@Configuration都改為使用@Component,結(jié)果仍然不變。
得出結(jié)論:
@order
指定加載順序還跟類的命名和存放位置有關(guān)!假如有Config1
和Config2
兩個(gè)類在一個(gè)包下,要求是Config2
先加載:
- 這時(shí)候設(shè)置
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
最關(guān)鍵的一句話:您可以在目標(biāo)類級(jí)別和@Bean方法上聲明@Order注釋,可能針對(duì)的是單個(gè)bean定義(如果多個(gè)定義使用同一個(gè)bean類)。@Order值可能會(huì)影響注入點(diǎn)的優(yōu)先級(jí),但請(qǐng)注意,它們不會(huì)影響單例啟動(dòng)順序,這是由依賴關(guān)系和@DependsOn聲明確定的正交關(guān)注。
我理解的注入點(diǎn)的優(yōu)先級(jí)應(yīng)該是指的存放容器的先后順序,也就是他并不會(huì)影響啟動(dòng)順序。
四、解決排序問題
我們不可能每次遇到這種問題又是改名又是換包的,所以,springboot提供了如下三個(gè)注解可以控制順序:
- @AutoConfigureAfter:當(dāng)前配置類在指定配置類之后執(zhí)行
- @AutoConfigureBefore:當(dāng)前配置類在指定配置類之前執(zhí)行
- @AutoConfigureOrder:指定優(yōu)先級(jí),數(shù)值越小,優(yōu)先級(jí)越高。
(1)首先將代碼改回原來的樣子
(2)在Config2使用@AutoConfigureBefore(Config1.class),代表的是在config1加載前進(jìn)行加載
@Configuration public class Config1 { public Config1() { System.out.println("Config1構(gòu)建了"); } } @Configuration @AutoConfigureBefore(Config1.class) public class Config2 { public Config2() { System.out.println("Config2構(gòu)建了"); } }
(3)輸出結(jié)果,顯然還是沒生效
可能有時(shí)候走了運(yùn)給你一種錯(cuò)覺還真的配置成功了。實(shí)際上這種方式是不可行的,以上三個(gè)注解只有針對(duì)自動(dòng)配置類才會(huì)生效。
在autoconfigure包下就有spring.factories,這個(gè)文件配置了自動(dòng)配置類,springboot會(huì)讀取這個(gè)文件的,我們也可以在自己項(xiàng)目上定義spring.factories,這樣我們的配置類對(duì)于@AutoConfigureAfter注解就可以生效了。
(4)自定義spring.factories
第一行是固定的,后面的就是全類名,雖然只有Config2使用了注解,但是需求是和Config1進(jìn)行排序,所以這兩個(gè)都得加。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.gzl.cn.springbootcache.config.Config2,\ com.gzl.cn.springbootcache.config.Config1
(5)測(cè)試,成功解決
五、排序源碼分析
針對(duì)于@AutoConfigure那三個(gè)注解原理:其實(shí)關(guān)鍵的代碼還是在AutoConfigurationImportSelector中,將自動(dòng)配置類從spring.factories加載出來之后會(huì)根據(jù)條件排序(只有自動(dòng)配置類!),在selectImports()方法中最后一行代碼如下:
緊接著會(huì)走到這個(gè)地方,實(shí)際上是分了三步排序:
- 先按照文件名字母排序
- 按照@AutoConfigureOrder進(jìn)行排序
- 按照 @AutoConfigureBefore和@AutoConfigureAfter排序
從上面配置的順序可以知道,最終決定權(quán)還是在@AutoConfigureAfter、@AutoConfigureBefore這兩個(gè)注解。
當(dāng)我們不設(shè)置spring.factories的時(shí)候,這里面壓根都沒有這兩個(gè)類!
六、@AutoConfigureOrder
這種也是可以的!當(dāng)然前提也是需要配置spring.factories
@Configuration @AutoConfigureOrder(2) public class Config1 { public Config1() { System.out.println("Config1構(gòu)建了"); } } @Configuration @AutoConfigureOrder(1) public class Config2 { public Config2() { System.out.println("Config2構(gòu)建了"); } }
總結(jié)
到此這篇關(guān)于Spring中@order注解用法的文章就介紹到這了,更多相關(guān)Spring @order注解用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置詳解
這篇文章主要給大家介紹了關(guān)于Springboot2.6.x的啟動(dòng)流程與自動(dòng)配置的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01Java Web項(xiàng)目創(chuàng)建并實(shí)現(xiàn)前后端交互
本文主要介紹了Java Web項(xiàng)目創(chuàng)建并實(shí)現(xiàn)前后端交互,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Spring AOP日志框架實(shí)現(xiàn)過程圖解
這篇文章主要介紹了Spring AOP日志框架實(shí)現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)
今天小編就為大家分享一篇關(guān)于Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)的文章,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10JDK1.8中ConcurrentHashMap中computeIfAbsent死循環(huán)bug問題
這篇文章主要介紹了JDK1.8中ConcurrentHashMap中computeIfAbsent死循環(huán)bug,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08如何在Spring中使用編碼方式動(dòng)態(tài)配置Bean詳解
這篇文章主要給大家介紹了關(guān)于如何在Spring中使用編碼方式動(dòng)態(tài)配置Bean的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05Spring內(nèi)置任務(wù)調(diào)度如何實(shí)現(xiàn)添加、取消與重置詳解
任務(wù)調(diào)度是我們?nèi)粘i_發(fā)中經(jīng)常會(huì)碰到的,下面這篇文章主要給大家介紹了關(guān)于Spring內(nèi)置任務(wù)調(diào)度如何實(shí)現(xiàn)添加、取消與重置的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10Spring Boot使用RestTemplate消費(fèi)REST服務(wù)的幾個(gè)問題記錄
這篇文章主要介紹了Spring Boot使用RestTemplate消費(fèi)REST服務(wù)的幾個(gè)問題記錄,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06