SpringBoot高级监听原理

Java监听机制中定义了以下几个角色:

  1. 事件:Event,继承java.util.EventObject类的对象
  2. 事件源:Source,任意对象Object;
  3. 监听器:Listener,实现java.util.EventListener接口的对象

SpringBoot的监听机制就是对Java的监听机制的封装。

SpringBoot监听机制

SpringBoot在项目启动时,会对几个监听器进行回调,我们可以实现这些监听器接口,在项目启动时完成一些操作。

SpringBoot中可以实现的监听器接口有四个:

  1. ApplicationContextInitializer
  2. SpringApplicationRunListener
  3. CommandLineRunner
  4. ApplicationRunner
    其中第三个和第四个功能类似,只是方法的参数类型不同。

示例

1、新建一个工程,分别实现上述四个监听器接口(ApplicationContextInitializer:虽然名字上没有监听器字眼,但是实现机制也是监听器的原理)
代码如下:

①实现 ApplicationContextInitializer 接口

@Component
public class MyApplicationContextInitializer implements ApplicationContextInitializer {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("ApplicationContextInitializer...");
    }

}

②实现 SpringApplicationRunListener 接口

@Component
public class MySpringApplicationRunListener implements SpringApplicationRunListener {

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("starting...项目启动中");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, 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 started(ConfigurableApplicationContext context) {
        System.out.println("started...上下文对象加载完成");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("running...项目启动完成,开始运行");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("failed...项目启动失败");
    }
}

③实现 CommandLineRunner 接口

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("CommandLineRunner#run");
    }
}

④实现 ApplicationRunner 接口

@Component
public class MyApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner#run");
    }
}

2、启动项目,控制台输出日志

可以看到只有MyCommandLineRunner 和 MyApplicationRunner 监听器启动并生效了,这两种监听器功能类似,实际使用时用其中一种即可

3、使MySpringApplicationRunListener 监听器生效

在resources目录下新建一个META-INF目录并新建一个spring.factories文件

文件内容为注册 MySpringApplicationRunListener 监听器

org.springframework.context.ApplicationContextInitializer=\
  com.winson.springbootlistener.listener.MyApplicationContextInitializer

再次启动项目,控制台日志如下,MySpringApplicationRunListener 生效,在banner打印之后,在spring的IOC容器启动前作用,实际应用时可以用作资源检测。

4、使 MySpringApplicationRunListener 监听器生效

我们在spring.factories文件将 MySpringApplicationRunListener 监听器也注册

org.springframework.context.ApplicationContextInitializer=\
  com.winson.springbootlistener.listener.MyApplicationContextInitializer
org.springframework.boot.SpringApplicationRunListener=\
  com.winson.springbootlistener.listener.MySpringApplicationRunListener

启动程序,报异常:java.lang.NoSuchMethodException: com.winson.springbootlistener.listener.MySpringApplicationRunListener.(org.springframework.boot.SpringApplication, [Ljava.lang.String;),说明我们自定义的监听器类需要有初始化方法,而且需要两个参数(org.springframework.boot.SpringApplication, [Ljava.lang.String;),一个是SpringApplication类型的参数,一个是String数组

我们找到 SpringApplicationRunListener 接口 的另一个实现类 EventPublishingRunListener 就有init方法,仿照该init方法,在我们自定义的实现类中也写一个init方法(参数也一致)

添加初始化方法(带参构造方法)后如下(类上的@Component注解删除,否则报错,无法注入SpringApplication)

public class MySpringApplicationRunListener implements SpringApplicationRunListener {

    public MySpringApplicationRunListener(SpringApplication application, String[] args) {
    }

    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("starting...项目启动中");
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, 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 started(ConfigurableApplicationContext context) {
        System.out.println("started...上下文对象加载完成");
    }

    @Override
    public void running(ConfigurableApplicationContext context) {
        System.out.println("running...项目启动完成,开始运行");
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("failed...项目启动失败");
    }
}

再次启动程序,控制台日志,发现 MySpringApplicationRunListener 监听器生效了,该监听器几乎作用在整个程序启动的生命周期里:

小结:实际工作中,我们就可以利用监听器,在程序启动的不同阶段设置具体的业务功能

下面简介SpringBoot中默认的监听器


在依赖中,我们发现SpringBoot已经定义了各个阶段的监听器,打开具体一个查看,其它的大家可以再逐一查看。

原文地址:https://www.cnblogs.com/elnimo/p/15641367.html