欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中如何控制bean的加載順序

 更新時(shí)間:2024年12月26日 09:01:42   作者:seven97_top  
springboot遵從約定大于配置的原則,極大程度的解決了配置繁瑣的問(wèn)題,在此基礎(chǔ)上,又提供了spi機(jī)制,用spring.factories可以完成一個(gè)小組件的自動(dòng)裝配功能,這篇文章主要介紹了如何控制bean的加載順序,需要的朋友可以參考下

寫(xiě)在前面

springboot遵從約定大于配置的原則,極大程度的解決了配置繁瑣的問(wèn)題。在此基礎(chǔ)上,又提供了spi機(jī)制,用spring.factories可以完成一個(gè)小組件的自動(dòng)裝配功能。

在一般業(yè)務(wù)場(chǎng)景,可能是不需要關(guān)心一個(gè)bean是如何被注冊(cè)進(jìn)spring容器的,只需要把需要注冊(cè)進(jìn)容器的bean聲明為@Component即可,因?yàn)閟pring會(huì)自動(dòng)掃描到這個(gè)Bean完成初始化并加載到spring上下文容器。

但是,如果加載Bean的過(guò)程中部分Bean和Bean之間存在依賴(lài)關(guān)系,也就是說(shuō)Bean A的加載需要等待Bean B加載完成之后才能進(jìn)行;或者你正在開(kāi)發(fā)某個(gè)中間件需要完成自動(dòng)裝配時(shí),你會(huì)聲明自己的Configuration類(lèi),但是可能你面對(duì)的是好幾個(gè)有互相依賴(lài)的Bean,如果不加以控制,這時(shí)候可能會(huì)報(bào)找不到依賴(lài)的錯(cuò)誤。

而Spring框架在沒(méi)有明確指定加載順序的情況下是無(wú)法按照業(yè)務(wù)邏輯預(yù)期的順序進(jìn)行Bean加載,所以需要Spring框架提供能讓開(kāi)發(fā)人員顯示地指定Bean加載順序的能力。

幾個(gè)誤區(qū)

在正式說(shuō)如何控制加載順序之前,先說(shuō)2個(gè)誤區(qū):

  • 在標(biāo)注了@Configuration的類(lèi)中,寫(xiě)在前面的@Bean一定會(huì)被先注冊(cè)嗎?

這個(gè)不存在的,spring在xml的時(shí)代,也不存在寫(xiě)在前面一定會(huì)被先加載的邏輯。因?yàn)閤ml不是漸進(jìn)的加載,而是全部parse好,再進(jìn)行依賴(lài)分析和注冊(cè)。到了springboot中,只是省去了xml被parse成spring內(nèi)部對(duì)象的這一過(guò)程,但是加載方式并沒(méi)有大的改變。

  • 利用@Order這個(gè)標(biāo)注就一定能進(jìn)行加載順序的控制嗎?

嚴(yán)格的說(shuō),不是所有的Bean都可以通過(guò)@Order這個(gè)標(biāo)注進(jìn)行順序的控制。因?yàn)榘?code>@Order這個(gè)標(biāo)注加在普通的方法上或者類(lèi)上是沒(méi)有影響的,

@Order能控制哪些bean的加載順序呢?官方解釋?zhuān)?/p>

java

{@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).

最開(kāi)始@Order注解用于切面的優(yōu)先級(jí)指定;在 4.0 之后對(duì)它的功能進(jìn)行了增強(qiáng),支持集合的注入時(shí),指定集合中 bean 的順序,并且特別指出了,它對(duì)于單實(shí)例的 bean 之間的順序,沒(méi)有任何影響。目前用的比較多的有以下3點(diǎn):

  • 控制AOP的類(lèi)的加載順序,也就是被@Aspect標(biāo)注的類(lèi)
  • 控制ApplicationListener實(shí)現(xiàn)類(lèi)的加載順序
  • 控制CommandLineRunner實(shí)現(xiàn)類(lèi)的加載順序

使用詳情請(qǐng)看后文

如何控制

@Conditional 條件注解家族

  • @ConditionalOnClass:當(dāng)類(lèi)路徑下存在指定的類(lèi)時(shí),配置類(lèi)才會(huì)生效。
@Configuration
// 當(dāng)類(lèi)路徑下存在指定的類(lèi)時(shí),配置類(lèi)才會(huì)生效。
@ConditionalOnClass(name = "com.example.SomeClass")
public class MyConfiguration {
	// ...
}
  • @ConditionalOnMissingClass:當(dāng)類(lèi)路徑下不存在指定的類(lèi)時(shí),配置類(lèi)才會(huì)生效。
  • @ConditionalOnBean:當(dāng)容器中存在指定的Bean時(shí),配置類(lèi)才會(huì)生效。
  • @ConditionalOnMissingBean:當(dāng)容器中不存在指定的Bean時(shí),配置類(lèi)才會(huì)生效。

@DependsOn

@DependsOn注解可以用來(lái)控制bean的創(chuàng)建順序,該注解用于聲明當(dāng)前bean依賴(lài)于另外一個(gè)bean。所依賴(lài)的bean會(huì)被容器確保在當(dāng)前bean實(shí)例化之前被實(shí)例化。

@DependsOn的使用:

  • 直接或者間接標(biāo)注在帶有@Component注解的類(lèi)上面;
  • 直接或者間接標(biāo)注在帶有@Bean注解的方法上面;
  • 使用@DependsOn注解到類(lèi)層面僅僅在使用 component-scanning 方式時(shí)才有效,如果帶有@DependsOn注解的類(lèi)通過(guò)XML方式使用,該注解會(huì)被忽略,<bean depends-on="..."/>這種方式會(huì)生效。

示例:

@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的加載順序?yàn)椋?/p>

bean B init
bean A init
bean E init
bean D init
bean C init

參數(shù)注入

@Bean標(biāo)注的方法上,如果傳入了參數(shù),springboot會(huì)自動(dòng)會(huì)為這個(gè)參數(shù)在spring上下文里尋找這個(gè)類(lèi)型的引用。并先初始化這個(gè)類(lèi)的實(shí)例。

利用此特性,我們也可以控制bean的加載順序。

示例:

@Bean
public BeanA beanA(BeanB demoB){
  System.out.println("bean A init");
  return new BeanA();
}
@Bean
public BeanB beanB(){
  System.out.println("bean B init");
  return new BeanB();
}

以上結(jié)果,beanB先于beanA被初始化加載。

需要注意的是,springboot會(huì)按類(lèi)型去尋找。如果這個(gè)類(lèi)型有多個(gè)實(shí)例被注冊(cè)到spring上下文,那就需要加上@Qualifier("Bean的名稱(chēng)")來(lái)指定

利用bean的生命周期中的擴(kuò)展點(diǎn)

在spring體系中,從容器到Bean實(shí)例化&初始化都是有生命周期的,并且提供了很多的擴(kuò)展點(diǎn),允許在這些步驟時(shí)進(jìn)行邏輯的擴(kuò)展。

這些可擴(kuò)展點(diǎn)的加載順序由spring自己控制,大多數(shù)是無(wú)法進(jìn)行干預(yù)的??梢岳眠@一點(diǎn),擴(kuò)展spring的擴(kuò)展點(diǎn)。在相應(yīng)的擴(kuò)展點(diǎn)加入自己的業(yè)務(wù)初始化代碼。從來(lái)達(dá)到順序的控制。

具體關(guān)于spring容器中大部分的可擴(kuò)展點(diǎn)的分析,之前已經(jīng)寫(xiě)了一篇文章詳細(xì)介紹了:Spring&SpringBoot中所有的擴(kuò)展點(diǎn)

實(shí)現(xiàn)Ordered/PriorityOrdered接口/注解

在Spring中提供了如下的方法來(lái)進(jìn)行Bean加載順序的控制:

  • 實(shí)現(xiàn)Ordered/PriorityOrdered接口,重寫(xiě)order方法
  • 使用@Order/@Priority注解,@Order注解可以用于方法級(jí)別,而@Priority注解則不行;

針對(duì)自定義的Bean而言,上述的方式都可以實(shí)現(xiàn)Bean加載順序的控制。無(wú)論是實(shí)現(xiàn)接口的方式還是使用注解的方式,值設(shè)置的越小則優(yōu)先級(jí)越高,而通過(guò)實(shí)現(xiàn)PriorityOrdered接口或者使用@Priority注解的Bean時(shí)其加載優(yōu)先級(jí)會(huì)高于實(shí)現(xiàn)Ordered接口或者使用@Order注解的Bean。

需要注意的是,使用上述方式只會(huì)改變實(shí)現(xiàn)同一接口Bean加載到集合(比如List、Set等)中的順序(或者說(shuō)優(yōu)先級(jí)),但是這種方式并不會(huì)影響到Spring應(yīng)用上下文啟動(dòng)時(shí)不同Bean的初始化順序(startup order)。

  • 錯(cuò)誤案例:以下案例代碼是無(wú)法指定配置順序的
@Component
@Order(1)
public class BeanA {
    // BeanA的定義
}
@Component
@Order(2)
public class BeanB {
    // BeanB的定義
}
  • 正確使用案例:

首先定義兩個(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());
        }
    }
}

@AutoConfigureOrder

這個(gè)注解用來(lái)指定配置文件的加載順序。但是在實(shí)際測(cè)試中發(fā)現(xiàn),以下這樣使用是不生效的:

@Configuration
@AutoConfigureOrder(2)
public class BeanOrderConfiguration1 {
    @Bean
    public BeanA beanA(){
        System.out.println("bean A init");
        return new BeanA();
    }
}
@Configuration
@AutoConfigureOrder(1)
public class BeanOrderConfiguration2 {
    @Bean
    public BeanB beanB(){
        System.out.println("bean B init");
        return new BeanB();
    }
}

無(wú)論你2個(gè)數(shù)字填多少,都不會(huì)改變其加載順序結(jié)果。那這個(gè)@AutoConfigureOrder到底是如何使用的呢?

@AutoConfigureOrder適用于外部依賴(lài)的包中 AutoConfig 的順序,而不能用來(lái)指定本包內(nèi)的順序。能被你工程內(nèi)部scan到的包,都是內(nèi)部的Configuration,而spring引入外部的Configuration,都是通過(guò)spring特有的spi文件:spring.factories

換句話說(shuō),@AutoConfigureOrder能改變spring.factories中的@Configuration的順序。

具體使用方式:

@Configuration
@AutoConfigureOrder(10)
public class BeanOrderConfiguration1 {
    @Bean
    public BeanA beanA(){
        System.out.println("bean A init");
        return new BeanA();
    }
}
@Configuration
@AutoConfigureOrder(1)
public class BeanOrderConfiguration2 {
    @Bean
    public BeanB beanB(){
        System.out.println("bean B init");
        return new BeanB();
    }
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.example.demo.BeanOrderConfiguration1,\
  com.example.demo.BeanOrderConfiguration2

總結(jié)

其實(shí)在工作中,我相信很多人碰到過(guò)復(fù)雜的依賴(lài)關(guān)系的bean加載,把這種不確定性交給spring去做,還不如我們自己去控制,這樣在閱讀代碼的時(shí)候 ,也能輕易看出bean之間的依賴(lài)先后順序。

到此這篇關(guān)于Java中如何控制bean的加載順序的文章就介紹到這了,更多相關(guān)java bean加載順序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 以Java代碼為例講解設(shè)計(jì)模式中的簡(jiǎn)單工廠模式

    以Java代碼為例講解設(shè)計(jì)模式中的簡(jiǎn)單工廠模式

    簡(jiǎn)單來(lái)說(shuō),工廠模式就是按照需求來(lái)返回一個(gè)類(lèi)型的對(duì)象,使用工廠模式的意義就是,如果對(duì)象的實(shí)例化與代碼依賴(lài)太大的話,不方便進(jìn)行擴(kuò)展和維護(hù),使用工廠的目的就是使對(duì)象的實(shí)例化與主程序代碼就行解耦.來(lái)具體看一下:
    2016-05-05
  • jdk-logging?log4j?logback日志系統(tǒng)實(shí)現(xiàn)機(jī)制原理介紹

    jdk-logging?log4j?logback日志系統(tǒng)實(shí)現(xiàn)機(jī)制原理介紹

    這篇文章主要介紹了jdk-logging、log4j、logback日志介紹以及三個(gè)日志系統(tǒng)的實(shí)現(xiàn)機(jī)制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Spring框架的ImportSelector詳細(xì)解讀

    Spring框架的ImportSelector詳細(xì)解讀

    這篇文章主要介紹了Spring框架的ImportSelector詳細(xì)解讀,Spring中一個(gè)非常重要的注解@Import中的ImportSelector接口的作用以及它到底有啥作用,也會(huì)捎帶一部分源碼說(shuō)一下DeferredImportSelector是干啥的,需要的朋友可以參考下
    2024-01-01
  • JPA 加鎖機(jī)制及@Version版本控制方式

    JPA 加鎖機(jī)制及@Version版本控制方式

    這篇文章主要介紹了JPA 加鎖機(jī)制及@Version版本控制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Mybatis延遲加載和緩存深入講解

    Mybatis延遲加載和緩存深入講解

    這篇文章主要給大家介紹了關(guān)于Mybatis延遲加載和緩存的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Java監(jiān)聽(tīng)器ActionListener與MouseListener的執(zhí)行順序說(shuō)明

    Java監(jiān)聽(tīng)器ActionListener與MouseListener的執(zhí)行順序說(shuō)明

    這篇文章主要介紹了Java監(jiān)聽(tīng)器ActionListener與MouseListener的執(zhí)行順序說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • eclipse創(chuàng)建springboot項(xiàng)目的三種方式總結(jié)

    eclipse創(chuàng)建springboot項(xiàng)目的三種方式總結(jié)

    這篇文章主要介紹了eclipse創(chuàng)建springboot項(xiàng)目的三種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot統(tǒng)一處理功能實(shí)現(xiàn)的全過(guò)程

    SpringBoot統(tǒng)一處理功能實(shí)現(xiàn)的全過(guò)程

    最近在做項(xiàng)目時(shí)需要對(duì)異常進(jìn)行全局統(tǒng)一處理,主要是一些分類(lèi)入庫(kù)以及記錄日志等,下面這篇文章主要給大家介紹了關(guān)于SpringBoot統(tǒng)一功能處理實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • 超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法

    超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法

    這篇文章主要介紹了超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • SpringBoot集成geodesy實(shí)現(xiàn)距離計(jì)算功能

    SpringBoot集成geodesy實(shí)現(xiàn)距離計(jì)算功能

    Geodesy:大地測(cè)量學(xué)的神奇力量 Geodesy,又稱(chēng)大地測(cè)量學(xué),是一門(mén)研究地球形狀、大小及其重力場(chǎng)的學(xué)科,在地球距離計(jì)算中,它扮演著至關(guān)重要的角色,故本文給大家介紹了SpringBoot集成geodesy實(shí)現(xiàn)距離計(jì)算功能,感興趣的朋友可以參考下
    2024-06-06

最新評(píng)論