zoukankan      html  css  js  c++  java
  • SpringBoot扩展点之一:SpringApplicationRunListener

    三种监听器的关系

    ApplicationListener、SpringApplicationRunListeners、SpringApplicationRunListener的关系:

    • SpringApplicationRunListeners类和SpringApplicationRunListener类是SpringBoot中新增的类。ApplicationListener是spring中框架的类。
    • 在SpringBoot(SpringApplication类)中,使用SpringApplicationRunListeners、SpringApplicationRunListener来间接调用ApplicationListener。
    • SpringApplicationRunListeners是SpringApplicationRunListener的封装,SpringApplicationRunListeners中包含多个SpringApplicationRunListener,是为了批量执行的封装,SpringApplicationRunListeners与SpringApplicationRunListener生命周期相同,调用每个周期的各个SpringApplicationRunListener。然后广播相应的事件到Spring框架的ApplicationListener。

    通过上面的3个特点可以看出SpringApplicationRunListener就是一个ApplicationListener的代理。springboot启动的几个主要过程的监听通知都是通过他来进行回调。

    SpringApplicationRunListener

    从命名我们就可以知道它是一个监听者,那纵观整个启动流程我们会发现,它其实是用来在整个启动流程中接收不同执行点事件通知的监听者,SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener类。

    源码如下:

    public interface SpringApplicationRunListener {
    
         //刚执行run方法时
        void started();
         //环境建立好时候
        void environmentPrepared(ConfigurableEnvironment environment);
         //上下文建立好的时候
        void contextPrepared(ConfigurableApplicationContext context);
        //上下文载入配置时候
        void contextLoaded(ConfigurableApplicationContext context);
        //上下文刷新完成后,run方法执行完之前
        void finished(ConfigurableApplicationContext context, Throwable exception);
    
    }

    它定义了5个步骤:

    1.   started(run方法执行的时候立马执行;对应事件的类型是ApplicationStartedEvent):通知监听器,SpringBoot开始执行
    2.   environmentPrepared(ApplicationContext创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent):通知监听器,Environment准备完成
    3.   contextPrepared(ApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件):通知监听器,ApplicationContext已经创建并初始化完成
    4.   contextLoaded(ApplicationContext创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent):通知监听器,ApplicationContext已经完成IoC配置价值
    5.   finished(run方法结束之前调用;对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent):通知监听器,SpringBoot启动完成

    实现类 EventPublishingRunListener类

    EventPublishingRunListener类 实现了SpringApplicationRunListener,它具有广播事件的功能。

    构造函数

    public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    
        private final SpringApplication application;
    
        private final String[] args;
    
        private final SimpleApplicationEventMulticaster initialMulticaster;
    
        public EventPublishingRunListener(SpringApplication application, String[] args) {
            this.application = application;
            this.args = args;
    //新建立广播器
    this.initialMulticaster = new SimpleApplicationEventMulticaster(); for (ApplicationListener<?> listener : application.getListeners()) { this.initialMulticaster.addApplicationListener(listener); } } //...

    从上面代码可以看出,它使用了Spring广播器SimpleApplicationEventMulticaster。它把监听的过程封装成了SpringApplicationEvent事件并让内部属性(属性名为multicaster)ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster广播出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。

    EventPublishingRunListener的initialMulticaster成员变量SimpleApplicationEventMulticaster,以及它的multicastEvent()和invokeListener()方法

    initialMulticaster是在构造函数中初始化的,见上面的代码片段。

    源码如下:

    @Override
        public void multicastEvent(ApplicationEvent event) {
            multicastEvent(event, resolveDefaultEventType(event));
        }
    
        @Override
        public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
            ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
            for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
                Executor executor = getTaskExecutor();
                if (executor != null) {
                    executor.execute(new Runnable() {
                        @Override
                        public void run() {
                            invokeListener(listener, event);
                        }
                    });
                }
                else {
                    invokeListener(listener, event);
                }
            }
        }

    和invokeListener()方法,其参数是ApplicationListener和ApplicationEvent

        protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
            ErrorHandler errorHandler = getErrorHandler();
            if (errorHandler != null) {
                try {
                    doInvokeListener(listener, event);
                }
                catch (Throwable err) {
                    errorHandler.handleError(err);
                }
            }
            else {
                doInvokeListener(listener, event);
            }
        }

    EventPublishingRunListener的5个方法:

    首先看下starting方法:

    public void starting() {
            this.initialMulticaster
                    .multicastEvent(new ApplicationStartedEvent(this.application, this.args));
        }

     ApplicationStartingEvent构造方法中传递了一个SpringApplication对象和args参数。一直传递到了父类EventObject,将SpringApplication对象存放在source变量中。

    EventObject类结构。getSource()方法得到的就是SpringApplication对象。

    所以说SpringApplicationRunListener和ApplicationListener之间的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系起来的。更多的spring事件知识见《ApplicationEvent事件机制源码分析

    如何扩展

    对于开发者来说,基本没有什么常见的场景要求我们必须实现一个自定义的SpringApplicationRunListener,即使是SpringBoot中也只默认实现了一个org.springframework.boot.context.eventEventPublishingRunListener, 用来在SpringBoot的整个启动流程中的不同时间点发布不同类型的应用事件(SpringApplicationEvent)。那些对这些应用事件感兴趣的ApplicationListener可以接受并处理(这也解释了为什么在SpringApplication实例化的时候加载了一批ApplicationListener,但在run方法执行的过程中并没有被使用)。

    ​  如果我们真的在实际场景中自定义实现SpringApplicationRunListener,有一个点需要注意:任何一个SpringApplicationRunListener实现类的构造方法都需要有两个构造参数,一个参数的类型就是我们的org.springframework.boot.SpringApplication,另外一个参数就是args参数列表的String[]:

    package com.dxz.controller;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.SpringApplicationRunListener;
    import org.springframework.context.ConfigurableApplicationContext;
    import org.springframework.core.env.ConfigurableEnvironment;
    
    public class SampleSpringApplicationRunListener implements SpringApplicationRunListener {
        private final SpringApplication application;
        private final String[] args;
    
        public SampleSpringApplicationRunListener(SpringApplication sa, String[] args) {
            this.application = sa;
            this.args = args;
        }
    
        @Override
        public void starting() {
            System.out.println("自定义starting");
        }
    
        @Override
        public void environmentPrepared(ConfigurableEnvironment environment) {
            System.out.println("自定义environmentPrepared");
        }
    
        @Override
        public void contextPrepared(ConfigurableApplicationContext context) {
            System.out.println("自定义contextPrepared");
        }
    
        @Override
        public void contextLoaded(ConfigurableApplicationContext context) {
            System.out.println("自定义contextLoaded");
        }
    
        @Override
        public void finished(ConfigurableApplicationContext context, Throwable exception) {
            System.out.println("自定义finished");
        }
    }

    接着,我们还要满足SpringFactoriesLoader的约定,在当前SpringBoot项目的classpath下新建META-INF目录,并在该目录下新建spring.fatories文件,文件内容如下:

    org.springframework.boot.SpringApplicationRunListener=
    com.dxz.SampleSpringApplicationRunListener
  • 相关阅读:
    正则表达式--验证中国手机号
    PostgreSQ数据库安全连接请求问题
    golang时间正反格式化
    Git 分支管理和冲突解决
    golang交叉编译
    ps命令
    Redis应用场景
    SecureCRT for Mac
    Redis作者谈Redis应用场景
    redis 五种数据的应用场景
  • 原文地址:https://www.cnblogs.com/duanxz/p/11243271.html
Copyright © 2011-2022 走看看