『深入学习 Spring Boot』(四) Spring Boot 中的监听器模式 (下)

594 阅读2分钟

前言

这节继续监听器。

Spring Boot 中的监听器模式

第一个事件

发布的第一个事件在 run 方法中:

public ConfigurableApplicationContext run(String... args) {
        // …………
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
    // …………
    }

然后,我们进入 getRunListeners(args) 方法中。

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger,
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }

又见到了熟悉的 getSpringFactoriesInstances方法了,我们去 spring.factoris中看一下SpringApplicationRunListener:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

嗯,这里只有一个实现。

我们再进入new SpringApplicationRunListeners()方法:

    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }

这个显然就是把 EventPublishingRunListener 赋值给了 listeners。

回到主线run()方法中接着调用了listeners.starting();

//     SpringApplicationRunListeners # starting()
public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
}

这里遍历 listeners ,调用starting()。事件上我们知道,listener中就一个EventPublishingRunListener

所以我们 直接进入EventPublishingRunListener#starting()方法:

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

ojbk,终于看见发布事件的动作了。

我们来看看,都有谁监听了它:

image-20210510223631280

看到了一个配置文件中的 listener:LoggingApplicationListener,看名字肯定跟日志有关系咯。

这个类太长了,不贴出来了。这个类就是用来启动 Spring Boot 的日志系统。

类注释:

一个配置LoggingSystem的ApplicationListener 。 如果环境包含logging.config属性,它将用于引导日志记录系统,否则将使用默认配置。

Spring Boot 启动时的事件

  • ApplicationStartingEvent

    Spring Boot 应用开始运行时发送,此时容器尚未初始化完成。

    // SpringApplication # run(String... args) # 301-302
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    
  • ApplicationEnvironmentPreparedEvent

    在 Spring 上下文创建之前发送,因为创建 Spring context 需要环境。

    // SpringApplication # prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) # 342
    listeners.environmentPrepared(environment);
    
  • ApplicationContextInitializedEvent

    Spring context 已准备好,初始化器已被调用完成。但 bean definitions 还未被加载。

    // SpringApplication # prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) # 368listeners.contextPrepared(context);
    
  • ApplicationPreparedEvent

    bean definitions 已加载完,在上下文刷新之前发送。

    // SpringApplication # prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) # 387listeners.contextLoaded(context);
    
  • ApplicationStartedEvent

    Spring context 已刷新,runners 被调用之前。

    // SpringApplication # run(String... args) # 318listeners.started(context);
    
  • ApplicationReadyEvent

    runners 被调用之后,表示 Spring Boot 已就绪了。

    // SpringApplication # run(String... args) # 327listeners.running(context);
    
  • ApplicationFailedEvent

    启动发生异常时,发送此事件。

    // SpringApplication # handleRunFailure(ConfigurableApplicationContext context, Throwable exception,Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) # 794listeners.failed(context, exception);
    

实践监听器

  1. 监听器定义

    我们就模仿LoggingApplicationListener来进行定义。

    public class OneListener implements GenericApplicationListener {    @Override    public boolean supportsEventType(ResolvableType eventType) {        return eventType.isAssignableFrom(ApplicationStartingEvent.class);    }    @Override    public void onApplicationEvent(ApplicationEvent event) {        System.out.println("yes,I am listening to you.");    }    @Override    public int getOrder() {        return Ordered.HIGHEST_PRECEDENCE + 20 +1;    }}
    
  2. 监听器注册

    1. 配置到 spring.factories

      org.springframework.context.ApplicationListener=\  com.example.indepthspringboot.springbootlistener.OneListener
      

      image-20210511213648053

    2. 硬编码添加

    3. application.properties属性配置context.listener.classes

      上述两种跟 初始化器类似。不重复实现了。

    4. @Component 注解

      但是只能用于 容器 创建之后的事件。因为在容器创建之前,该类并没有被加载进去。

      @Componentpublic class TwoListener implements GenericApplicationListener {    @Override    public boolean supportsEventType(ResolvableType eventType) {        return eventType.isAssignableFrom(ApplicationStartedEvent.class);    }     @Override    public void onApplicationEvent(ApplicationEvent event) {        System.out.println("yes,I am registered. and, I am listening to ApplicationStartedEvent");    }}
      

      image-20210511214444352

      然后,我们把监听事件修改为 ApplicationStartingEvent。 ​ image-20210511214621616 哦豁,没有监听成功。

总结

Spring Boot 中的监听器,其实是很复杂的。我们这里只是挑选了一部分进行学习。

先泛泛地过一遍,了解其大概原理,这样以后再深入地看的时候,也不会犯怵了。

在翻阅了 Spring Boot 中监听器部分时,还是有不少收获的:

  • 了解了 监听器模式 的实践运用。
  • 监听器模式的扩展用法。
  • 监听的事件还可以用泛型来表示
  • ……