[Day - 13] - Spring 依赖性注入元件管理运作与方法

Abstract

无论何种时候,每种系统的开发元件势必都有先後启动顺序,如何有效管控每项元件的启动流程相当重要,今天将介绍一个依赖性注册的注解模式给大家,依赖式注解(@DependOn)可让开发者评估哪些元件的先後注册顺序,减少元件注册的冲突,避免相关物件依赖错误,进而导致启动失败,在Spring Boot注册逻辑中,是采用字母排序进行注册,故开发者可自行来透过依靠模式注解来进行决定自身所开发的元件注册先後顺序,但须注意,昨日所述懒惰式(@Lazy)注册会无法产生效用,除非前後两者都加入懒惰式(@Lazy)注册,并无相关类别再启动时有所依赖,才会进行跳过,以下将介绍相关范例与原理介绍。

Principle Introduction

在Spring Boot中,我们都知道所有的元件都会注册进BeanFactory配置池中,在依靠模式注解中,会先判断是否存在此项元件,若不存在就以寻找此依靠物件为主进行注册,若找不到则会抛出“No bean named '*********' available,若找到则会在分析是否又有下一个依靠元件,以树状模式寻找到没有依靠元件为主,并会从每个类别的元件名称寻找至每个方法的Bean名称,当注册完该元件候,会再循序往下寻找未注册之元件,进行後续元件注册,以下面范例为例,透过此范例来分析与否采用依靠式注解的结果。

配置等待CompiledLanguage元件注册完後才可进行注册


@Service("InterpretedLanguageService")
@DependsOn("CompiledLanguageService")
public class InterpretedLanguServiceImpl implements ProgramLangService {

    @PostConstruct
    public void init() {
        System.out.println("InterpretedLanguServiceImpl initial after CompiledLanguage.");
    }

    ......
    ......
    ......
    ......
}

亦可等待各类方法的上的Bean元件

@Configuration
@DependsOn("InterpretedLanguageService")
public class NewLanguageConfiguration {

    @PostConstruct
    public void init() {
        System.out.println("NewLanguageConfiguration initial after InterpretedLanguage.");
    }

    @Bean("GoBean")
    public ProgramLangMdl getProgramLangMdlWithGo() {
       return new ProgramLangMdl()
                .setId("id-005")
                .setName("GoLang")
                .setDescritpion("Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.");
    }

    @Bean("LuaBean")
    @DependsOn("GoBean")
    public ProgramLangMdl getProgramLangMdlWithLua() {
        return new ProgramLangMdl()
                .setId("id-006")
                .setName("Lua")
                .setDescritpion("Lua is a lightweight, high-level, multi-paradigm programming language designed primarily for embedded use in applications. Lua is cross-platform, since the interpreter of compiled bytecode is written in ANSI C,[4] and Lua has a relatively simple C API to embed it into applications.");
    }
}

透过上面各类的方法依靠方式注解,可以得到以下结果,区块一为未采用依赖式注解(DependOn)的结果,根据实验结果仅透过字母排序进行注册,区块二为采用依赖式注解(DependOn)的结果,可由初始化结果得知注册的先後顺序,故此注解可决定初始化注册顺序,亦可决定销毁的先後顺序,因销毁顺序为注册顺序索引再相反进行销毁删除,提供开发者作参考。

区块一 未采用依靠式方法

CompiledLangServiceImpl initial.
CompiledLanguageService is afterPropertiesSet
FuturePopLanguageServiceImpl initial after LuaBean,GoBean.
FutureLanguageService is afterPropertiesSet
InterpretedLanguServiceImpl initial after CompiledLanguage.
InterpretedLanguageService is afterPropertiesSet
NewLanguageConfiguration initial after InterpretedLanguage.
NewLanguageConfiguration is afterPropertiesSet
2021-08-31 01:19:39.816  INFO 16416 --- [    Test worker] sw.project.sample.DepondOnTestSuite      : Started DepondOnTestSuite in 2.144 seconds (JVM running for 3.316)
Get Compiled object test success.
Get Bean object test success.
Get Bean object test success.
NewLanguageConfiguration is destroy
InterpretedLanguageService is destroy
FutureLanguageService is destroy
CompiledLanguageService is destroy

区块二 采用依靠式方法

CompiledLangServiceImpl initial.
CompiledLanguageService is afterPropertiesSet
InterpretedLanguServiceImpl initial after CompiledLanguage.
InterpretedLanguageService is afterPropertiesSet
NewLanguageConfiguration initial after InterpretedLanguage.
NewLanguageConfiguration is afterPropertiesSet
FuturePopLanguageServiceImpl initial after LuaBean,GoBean.
FutureLanguageService is afterPropertiesSet
2021-08-31 01:17:02.475  INFO 16392 --- [    Test worker] sw.project.sample.DepondOnTestSuite      : Started DepondOnTestSuite in 2.086 seconds (JVM running for 3.459)
Get Bean object test success.
FutureLanguageService is destroy
NewLanguageConfiguration is destroy
InterpretedLanguageService is destroy
CompiledLanguageService is destroy

Structure

透过架构图可知,一个Bean的生成会封装成BeanDefinition,透过ClassPathBeanDefintionScanner中的doScan方法,,然後在进入processCommonDefinitionAnnotations过滤各类注解模式服务,分别为@Lazy、@Primary、@DependsOn、@Role及@Description,当分析到该元件有配置依赖关系注解,则会在BeanDefinition进行触发setDependsOn方法,当所有注解模式过滤配置完後,即可透过代理模式配置成BeanDefinitionHolder,最後在进行注册该BeanDefinition,即可完成分析过滤依赖关系注解。
image

Follow up

Run test task

gradle test

Run open result html

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

Test Report

Depend-on register test report
image

Mind-blowing Depend-on register flow & test detail
image

Sample Source

spring-sample-dependOn

Reference Url

DependOn

Spring中@DependsOn注解的作用及实现原理解析


<<:  DAY13-EXCEL统计分析:F分配之介绍

>>:  Day13 X CSS GPU Acceleration

Day30:总结

一开始 30天以前,我以为我会放弃,刚开始一天要花4到6小时才能产出一篇文章,这样的状态维持了一周後...

硬体的讯号怎麽丢给软件?

预设 先要有一个开发板,可以接各种sensor。 可以先跟电脑有实体连接,这样就有指定的port可以...

Day 26 - XSS 与防范输入相关攻击的方式

倒数五天!倒数五天!倒数五天! 出於书本 Chapter 14. Web sites and Ap...

下载Python

上两天说了这麽多 我们今天就来下载Python编辑器来开始写程序吧。 首先,我们要先在浏览器上搜寻P...

Day26 Flutter 的状态管理 Provider (五) Firebase Login

main,dart: import 'package:firebase_core/firebase_...