[Day - 17 ] - Spring 导入选择器原理与开发

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 20 Hero动画

>>:  【第十八天 - Flutter Cloud Messaging(下)】

30.Action

Vuex的Action,相当於component内的methods,里面宣告并使用方法,但不会直接改...

Day26 语法改革!零基础新手也能读懂的JS - addEventListener(下)

今天来介绍网页相关事件、表单相关事件、剪贴相关事件吧! 网页相关事件 load:在载入元素时触发,不...

透过数位逻辑电路学习 Bitwise 操作

本文目标 学习基础的数位逻辑概念 认识撰写系统软件常用的 Bitwise 技巧 位移操作 认识多工器...

Day10-Go结构Struct

前言 今天要介绍 Go 语言的另一种资料型态,在先前,我们介绍的变数都是储存单一的值或是多个相同型态...

Day 5 | Fragment

Fragment(碎片)是Activity中可重复利用的使用者介面,必须依附於Activity,因此...