您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“SpringBoot中Bean的搭建方法和加載順序的錯(cuò)誤姿勢(shì)說(shuō)明”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)建一個(gè) maven 項(xiàng)目,pom 文件如下(具體的項(xiàng)目代碼,可以在文末獲?。?/p>
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7</version> <relativePath/> <!-- lookup parent from update --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </pluginManagement> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
下面我們會(huì)介紹兩種典型注解的錯(cuò)誤使用姿勢(shì),一個(gè)@Order
,一個(gè)@AutoConfigureOrder
一種常見的錯(cuò)誤觀點(diǎn)是在類上添加這個(gè) Order 注解,就可以指定 bean 之間的初始化順序,order 值越小,則優(yōu)先級(jí)越高,接下來(lái)我們實(shí)際測(cè)試一下,是否如此
我們創(chuàng)建兩個(gè) DemoBean, 指定不同的 Order 順序
@Order(4) @Component public class BaseDemo1 { private String name = "base demo 1"; public BaseDemo1() { System.out.println(name); } } @Order(3) @Component public class BaseDemo2 { private String name = "base demo 2"; public BaseDemo2() { System.out.println(name); } }
根據(jù)前面的觀點(diǎn),orde 值小的優(yōu)先級(jí)高,那么 BaseDemo2 應(yīng)該先被初始化,實(shí)際測(cè)試一下,輸出如下
Bean 除了上面的自動(dòng)掃描之外,還有一種方式就是通過(guò)@Bean
注解,下面我們演示一下在配置類中指定 bean 加載順序的錯(cuò)誤 case
同樣我們新建兩個(gè)測(cè)試 bean
public class BaseDemo3 { private String name = "base demo 3"; public BaseDemo3() { System.out.println(name); } } public class BaseDemo4 { private String name = "base demo 4"; public BaseDemo4() { System.out.println(name); } }
接下來(lái)在配置類中定義 bean
@Configuration public class ErrorDemoAutoConf { @Order(2) @Bean public BaseDemo3 baseDemo3() { return new BaseDemo3(); } @Order(1) @Bean public BaseDemo4 baseDemo4() { return new BaseDemo4(); } }
同樣的,如果@Order
注解有效,那么BaseDemo4
應(yīng)該先被初始化
從上面的實(shí)際測(cè)試輸出可以看出,@Order 注解在上面的方式中也不生效,如果有興趣的同學(xué)可以試一下,將上面配置類中的兩個(gè)方法的順序顛倒一下,會(huì)發(fā)現(xiàn)BaseDemo4
先加載
這也是一種常見的錯(cuò)誤 case,認(rèn)為@Order 注解是用來(lái)指定配置類的加載順序的,然而真的是這樣么?
我們創(chuàng)建兩個(gè)測(cè)試的配置類
@Order(1) @Configuration public class AConf { public AConf() { System.out.println("AConf init!"); } } @Order(0) @Configuration public class BConf { public BConf() { System.out.println("BConf init"); } }
如果@Order 注解生效,那么 BConf 配置類會(huì)優(yōu)先初始化,那么我們實(shí)測(cè)一下
從上面的結(jié)果可以看出,并不是 BConf 先被加載;當(dāng)然這種使用姿勢(shì),實(shí)際上和第一種錯(cuò)誤 case,并沒(méi)有什么區(qū)別,配置類也是 bean,前面不生效,這里當(dāng)然也不會(huì)生效
那么是不是我們的理解不對(duì)導(dǎo)致的呢,實(shí)際上這個(gè)@Order
放在配置類上之后,是這個(gè)配置類中定義的 Bean 的優(yōu)先于另一個(gè)配置類中定義的 Bean 呢?
同樣的我們測(cè)試下這種 case,我們定義三個(gè) bean,兩個(gè) conf
public class Demo1 { private String name = "conf demo bean 1"; public Demo1() { System.out.println(name); } } public class Demo2 { private String name = "conf demo bean 2"; public Demo2() { System.out.println(name); } } public class Demo3 { private String name = "conf demo bean 3"; public Demo3() { System.out.println(name); } }
然后我們將 Demo1, Demo3 放在一個(gè)配置中,Demo2 放在另外一個(gè)配置中
@Order(2) @Configuration public class AConf1 { @Bean public Demo1 demo1() { return new Demo1(); } @Bean public Demo3 demo3() { return new Demo3(); } } @Order(1) @Configuration public class BConf1 { @Bean public Demo2 demo2() { return new Demo2(); } }
如果@Order 注解實(shí)際上控制的是配置類中 Bean 的加載順序,那么 BConf1 中的 Bean 應(yīng)該優(yōu)先加載,也就是說(shuō) Demo2 會(huì)優(yōu)先于 Demo1, Demo3,實(shí)際測(cè)試一下,輸出如
上面的輸出結(jié)果和我們預(yù)期的并不一樣,所以@Order
注解來(lái)決定配置類的順序也是不對(duì)的
從命名來(lái)看,這個(gè)注解是用來(lái)指定配置類的順序的,然而對(duì)于這個(gè)注解的錯(cuò)誤使用也是非常多的,而大多的錯(cuò)誤使用在于沒(méi)有真正的了解到它的使用場(chǎng)景
接下來(lái)我們來(lái)演示一下錯(cuò)誤的使用 case
在工程內(nèi)新建兩個(gè)配置類,直接使用注解
@Configuration @AutoConfigureOrder(1) public class AConf2 { public AConf2() { System.out.println("A Conf2 init!"); } } @Configuration @AutoConfigureOrder(-1) public class BConf2 { public BConf2() { System.out.println("B conf2 init!"); } }
當(dāng)注解生效時(shí),BConf 會(huì)優(yōu)先級(jí)加載
從輸出結(jié)果來(lái)看,和我們預(yù)期的不一樣;那么這個(gè)注解是不是作用于配置類中的 Bean 的順序,而不是配置類本身呢?
同樣的我們?cè)O(shè)計(jì)一個(gè) case 驗(yàn)證一下
public class DemoA { private String name = "conf demo bean A"; public DemoA() { System.out.println(name); } } public class DemoB { private String name = "conf demo bean B"; public DemoB() { System.out.println(name); } } public class DemoC { private String name = "conf demo bean C"; public DemoC() { System.out.println(name); } }
對(duì)應(yīng)的配置類
@Configuration @AutoConfigureOrder(1) public class AConf3 { @Bean public DemoA demoA() { return new DemoA(); } @Bean public DemoC demoC() { return new DemoC(); } } @Configuration @AutoConfigureOrder(-1) public class BConf3 { @Bean public DemoB demoB() { return new DemoB(); } }
如果 DemoB 后被加載,則說(shuō)明上面的觀點(diǎn)是錯(cuò)誤的,實(shí)測(cè)結(jié)果如下
所以問(wèn)題來(lái)了,@AutoConfigureOrder
這個(gè)注解并不能指定配置類的順序,還叫這個(gè)名,干啥?存粹是誤導(dǎo)人不是!!!
接下來(lái)我們看一下@Order
和@AutoConfigureOrder
的正確使用方式
先看一下這個(gè)注解的官方注釋
{@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 注解用于切面的優(yōu)先級(jí)指定;在 4.0 之后對(duì)它的功能進(jìn)行了增強(qiáng),支持集合的注入時(shí),指定集合中 bean 的順序
并且特別指出了,它對(duì)于但實(shí)例的 bean 之間的順序,沒(méi)有任何影響;這句話根據(jù)我們上面的測(cè)試也可以驗(yàn)證
接下來(lái)我們需要看一下通過(guò)@Order 注解來(lái)注入集合時(shí),指定順序的場(chǎng)景
首先我們定義兩個(gè) Bean 實(shí)現(xiàn)同一個(gè)接口,并添加上@Order
注解
public interface IBean { } @Order(2) @Component public class AnoBean1 implements IBean { private String name = "ano order bean 1"; public AnoBean1() { System.out.println(name); } } @Order(1) @Component public class AnoBean2 implements IBean { private String name = "ano order bean 2"; public AnoBean2() { System.out.println(name); } }
然后再一個(gè)測(cè)試 bean 中,注入IBean
的列表,我們需要測(cè)試這個(gè)列表中的 Bean 的順序是否和我們定義的@Order
規(guī)則一致
@Component public class AnoTestBean { public AnoTestBean(List<IBean> anoBeanList) { for (IBean bean : anoBeanList) { System.out.println("in ano testBean: " + bean.getClass().getName()); } } }
根據(jù)我們的預(yù)期, anoBeanList 集合中,anoBean2 應(yīng)該在前面
根據(jù)上面的輸出,也可以看出列表中的順序和我們預(yù)期的一致,并且 AnoOrderBean1
與 AnoOrderBean2
的加載順序和注解沒(méi)有關(guān)系
這個(gè)注解用來(lái)指定配置文件的加載順序,然而前面的測(cè)試中并沒(méi)有生效,那么正確的使用姿勢(shì)是怎樣的呢?
@AutoConfigureOrder
適用于外部依賴的包中 AutoConfig 的順序,而不能用來(lái)指定本包內(nèi)的順序
為了驗(yàn)證上面的說(shuō)法,我們?cè)俅涡陆▋蓚€(gè)工程,并指定自動(dòng)配置類的順序
工程一配置如下:
@AutoConfigureOrder(1) @Configuration @ComponentScan(value = {"com.git.hui.boot.order.addition"}) public class AdditionOrderConf { public AdditionOrderConf() { System.out.println("additionOrderConf init!!!"); } }
注意自動(dòng)配置類如要被正確加載,需要在工程的 /META-INF/spring.factories
文件中定義
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.git.hui.boot.order.addition.AdditionOrderConf
工程二的配置如下:
@Configuration @AutoConfigureOrder(-1) @ComponentScan("com.git.hui.boot.order.addition2") public class AdditionOrderConf2 { public AdditionOrderConf2() { System.out.println("additionOrderConf2 init!!!"); } }
然后我們?cè)陧?xiàng)目?jī)?nèi)部添加一個(gè)配置
@AutoConfigureOrder(10) @Configuration public class OrderConf { public OrderConf() { System.out.println("inner order conf init!!!"); } }
因?yàn)樽⒔膺m用于外部依賴包中的自動(dòng)配置類的順序,所以上面三個(gè)配置類中,正確的話 AdditionOrderConf2 在 AdditionOrderConf1 之前;而 OrderConf 并不會(huì)收到注解的影響,默認(rèn)環(huán)境下,內(nèi)部定義的配置類會(huì)優(yōu)于外部依賴,從下面的輸出也可以佐證我們說(shuō)明(當(dāng)然為了驗(yàn)證確實(shí)如次,還應(yīng)該調(diào)整下兩個(gè)外部工程配置類的順序,并觀察下加載順序是否隨之改變,我們這里省略掉了)
“SpringBoot中Bean的搭建方法和加載順序的錯(cuò)誤姿勢(shì)說(shuō)明”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。