spring-boot自定义容器初始化组件

云中志

共 3972字,需浏览 8分钟

 · 2021-09-17

前言

前段时间我们在分享spring boot启动过程的时候,提到有几个dome要分享下,至于分享这些dome的原因主要有以下几点,第一点是结合spring boot启动过程从实践的角度看这些组件的用法和作用;第二点是,从源码的角度发掘spring boot潜在的高级知识点,学习和消化这些知识点,实现自我提升,所以从今天开始我们会逐一把前面说的demo分享出来,今天我们先来看下容器初始化组件——ApplicationContextInitializer

自定义初始化组件

初始化组件

定义一个初始化组件,实现ApplicationContextInitializer,然后在initialize方法中写入我们要进行的初始化操作:

/**
 * 自定义容器初始化类
 *
 * @author syske
 * @version 1.0
 * @date 2021-09-15 8:02
 */

public class SyskeInitializer implements ApplicationContextInitializer {
    private Logger logger = LoggerFactory.getLogger(SyskeInitializer.class);
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        logger.info("====================start======================");
        logger.info("SyskeInitializer initialize方法被执行……");
        logger.info("ApplicationName: {}", configurableApplicationContext.getApplicationName());
        logger.info("isActive: {}", String.valueOf(configurableApplicationContext.isActive()));
        logger.info("====================end======================");
    }
}

这样我们的初始化组件就写好了。

配置

resources文件夹下创建META-INF文件夹,并在其下创建sping.factories文件,具体结构如下:

然后在spring.factories文件中加入初始化组件的配置:

org.springframework.context.ApplicationContextInitializer=io.github.syske.springbootlearning.initializer.SyskeInitializer

这里的org.springframework.context.ApplicationContextInitializer就是我们前面实现的初始化接口,io.github.syske.springbootlearning.initializer.SyskeInitializer就是我们的初始化组件的具体实现,加这个配置的作用有两点,一个就是让spring boot能够识别我们自己增加的组件,二一个就是声明我们组件的类型是org.springframework.context.ApplicationContextInitializer,这样spring boot在启动的过程中就会按初始化组件进行处理。

这种配置方式通常被称作SPI机制(Service Provider Interface),在各类第三方框架中经常出现,比如dubbospring boot,通过这种方式既可以为框架提供各种扩展,同时又可以降低框架与扩展之间的依赖,可以实现有效解耦,确实很方便,当然也很强大。

spring boot中除了org.springframework.context.ApplicationContextInitializer之外,还为我们提供了如下扩展:

  • org.springframework.boot.env.PropertySourceLoaderProperty资源加载器
  • org.springframework.boot.SpringApplicationRunListener:容器运行监听器
  • org.springframework.boot.SpringBootExceptionReporter:异常报告器
  • org.springframework.context.ApplicationListener:应用监听器
  • org.springframework.boot.env.EnvironmentPostProcessor:环境变量后置处理器
  • org.springframework.boot.diagnostics.FailureAnalyzer:失败分析器
  • org.springframework.boot.diagnostics.FailureAnalysisReporter:失败分析报告器

当然,以上这些可能补充的也不是很完整,这里仅供参考。用法上和我们今天演示的ApplicationContextInitializer基本上都是一样的,各位小伙伴可以自行尝试。

另外需要提一点的是,spring-bootstarter也是基于spring.factories来实现的,感兴趣的小伙伴可以回顾下:

启动测试

完成以上代码编写和配置工作以后,我们直接运行启动spring boot,然后会在控制台输出我们在initialize方法输出的内容:

从上面的启动日志中,我们可以发现,ApplicationContextInitializer组件是紧挨着banner打印被执行的,结合我们最近分析的启动过程,我们可以知道,初始化组件是在prepareContext方法中被执行的,而这个方法是紧挨着容器创建的:

setInitializer方法这里我们可以看到,我们自己定义的ApplicationContextInitalizer已经被注册到initializers中了

加载过程分析

具体的配置和用法分享完了,下面我们结合最近研究的spring boot启动过程分析下spring.factories的加载过程。

spring.factories文件需要放在META-INF文件夹下,注意观察文件名,我们可以发现,文件后缀刚好是factory的复数形式,这也说明了这个文件的用途。它是在run方法中被解析的,更准确的说是在实例化SpringApplication的时候被解析的:

首先我们在程序主入口中调用了SpringApplication的静态方法run

然后静态run方法调用了另一个静态run,并在第二个静态run方法内部实例化SpringApplication

实例化SpringApplication的时候,会同步调用setInitializers(紧挨着的setListeners是设置应用监听器的),这里设置的就是容器初始化组件(包括我们自定义的),这里获取初始化组件的方法getSpringFactoriesInstances其内部进行了spring.factories文件的解析操作:

下面就是getSpringFactoriesInstances方法的内部实现:

其中的SpringFactoriesLoader.loadFactoryNames就是解析并获取spring.factories文件中的Factory的名字,然后将最终结果放进缓存中并返回:

总结

今天我们分享了自定义初始化组件,演示了定义过程、配置方式以及最终测试结果,整体来说整个过程还是比较简单的,当然重要的还是如何将这一组件和我们的具体业务相结合,实现我们具体的业务,这应该才是我们应该思考的。好了,关于spring boot初始化组件我们暂时就分享这么多,有兴趣的小伙伴可以亲自动手试一下。

- END -


浏览 32
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报