iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0

Abstract

我們前面已經討論了相當多種取得Bean的方法,如:自動注入(@Autowired、@Resource)或透過BeanFactory進行取得相關Bean元件,但的多開發者都會思考,如果有一種元件能夠一次將所想要的相關Bean類別自動注入成一個集合,並能夠提供給開發者所選擇想要的Bean類別進行過濾,可以更加便利的混雜各類元件的進行注入,這邊給各位開發者一個新的元件是透過外部配置做核心接口,稱為ImportSelector接口,在SpringBoot 中自動化配置和 @Enable相關的(功能性注解)核心原理都是它,此接口只有一個方法,返回需要的@Import的類別或相關Bean元件,透過這種方式我們可更加快速的一次注入性相當多的關聯元件,下面我們要來帶大家進一步討論。

Principle Introduction

Spring 框架所提供的導入選擇器目的在於提供一個或多個元件進行導入,他允許導入三種類型的程式碼,分別為Bean組態類型(@Configuration)、連結選擇器配置類型(@ImportSelector)及連結Bean定義註冊類型(@ImportBeanDefinitionRegistrar)三種類型,第一項Bean組態類型可包括所有元組件(@Component)擴展類型皆可整合,如:倉儲(@Repository)、服務(@Service)、元件(@Component)及組態(@Configuration)等註解模式,並逐一放入一個JSON格式數據集合,第二項連結選擇器配置類型,僅可在JSON格式數據中置放類別路徑字串,第三項Bean定義註冊類型,可在此層配置相關屬性值及相關Bean定義資料,常應用於啟動何種資料應用為主,如Spring @EnableXXX皆採用此種方式,開發者需包裝成列表元件(List)取得此外部配置的相關元件,相關範例我們可看以下程式碼。

範例一、導入選擇器範例程式碼,我們可將有定義或無定義元件的類別路徑放置入選擇導入器中,並在配置於組態內,提供各服務或相關測試進行運用。

//Set up ImportSelector
public class MarketImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {NorthMarketServiceImpl.class.getName(), SouthMarketServiceImpl.class.getName()};
    }
}

//Import MarketImportSelector into Configuration
@Configuration
@Import({MarketImportSelector.class,AppConfig.class})
public class MarketConfiguration {
}

//Injection components into List
public class MarketSerivceTestSuite extends ServiceTestBase {

    @Autowired
    private List<MarketService> marketServices;

  ...
  ...
  ...
  
      @Test
    public void testPrintMarketArea() {
        this.marketServices.forEach(MarketService::getMarketArea);
    }
    
}

範例一測試結果,一次取得兩項MarketService並可印出結果

 INFO 42455 --- [    Test worker] sw.spring.sample.MarketSerivceTestSuite  : Started MarketSerivceTestSuite in 2.327 seconds (JVM running for 3.973)
Taiwan North
Taiwan South

範例二、加入@Configuration中的Bean組件,並組合成一個列表(List)

//配置Bean組件
@Configuration
public class AppConfig {

    @Bean("WeistingMarket")
    public MarketMdl getWeistingMarket() {
        return new MarketMdl().setName("Weisting Market")
                            .setDescription("Created by Weisting.");
    }

    @Bean("JyunMarket")
    public MarketMdl getJyunMarket() {
        return new MarketMdl().setName("Jyun Market")
                .setDescription("Created by Jyun.");
    }

}

//Import App Config Bean into MarketConfiguration
@Configuration
@Import({MarketImportSelector.class,AppConfig.class})
public class MarketConfiguration {
}

//Test case
public class MarketSerivceTestSuite extends ServiceTestBase {

    @Autowired
    private List<MarketMdl> marketMdls;
    
    
    @Test
    public void testBeanContent() {
        Assertions.assertTrue(context.containsBean("WeistingMarket"));
        Assertions.assertTrue(context.containsBean("JyunMarket"));
        marketMdls.forEach( marketMdl -> {
            System.out.println(MessageFormat.format("Name : {0} , Description : {1}", marketMdl.getName(),marketMdl.getDescription()));
        });
        System.out.println("Verify Weisting and Jyun Bean success.");
    }

}

範例二測試結果確認取得兩個Bean組件

INFO 42526 --- [    Test worker] sw.spring.sample.MarketSerivceTestSuite  : Started MarketSerivceTestSuite in 2.371 seconds (JVM running for 3.978)
Name : Weisting Market , Description : Created by Weisting.
Name : Jyun Market , Description : Created by Jyun.
Verify Weisting and Jyun Bean success.

透過以上兩項簡單範例提供給各位開發者,小編認為這種相當適合運用條列式支援產品清單使用,亦可確認哪些產品以提供相關服務介接,可減少組態檔文件配置。

Structure

圖一 處理導入元件流程圖
image

根據上圖可知,Spring框架會先行初始化應用程式內容處理器,並進行BeanFactory配置池註冊流程,並過濾及處理相關組態流程,等待所有載入元件皆配置後,才開始進行判斷三項配置類型是否存在,分別為:ImportSelector、ImportBeanDefinitionRegistrar及@Configuration三項類型配置組件,並將其相關類別實例化,分別放置入集合中,當開發者進行注入對應類別物件,Spring框架會自動將對應類別物件整合成一個集合注入對應宣告欄位,透過以上介紹提供給各位讀者做參考。

Follow up

Run test task

gradle test

Run open result html

open ./build/reports/tests/test/index.html

Test Report

Import Selector test report
image

Mind-blowing selector import test description
image

Sample Source

spring-sample-selector

Reference Url

深入理解Spring的ImportSelector接口

Spring 源码分析之 ImportSelector 工作原理

死磕源码系列【ImportSelector接口原理解析】


上一篇
[Day - 16] - Spring 快取上手一天就搞定
下一篇
[Day - 18] - Spring SOA架構之領域驅動設計之旅
系列文
Wow ! There is no doubt about Learn Spring framework in a month.30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言