大家都知道,在 Spring 框架中事件和监听无处不在,打通了 Spring 框架的任督二脉,事件和监听也是 Spring 框架必学的核心知识之一。
一般来说,我们很少会使用到应用程序事件,但我们也不要忘了它们的存在,比如说在 Spring 框架内部都使用了各种不同的事件来处理不同的任务。
毫无疑问,在 Spring Boot 框架中,事件和监听也得到了发扬光大,除了常用的 Spring Framework 事件(例如:ContextRefreshedEvent)之外,Spring Boot 在启动过程中还发送一系列其他的应用程序事件。

Spring Boot 启动事件顺序

1、ApplicationStartingEvent
这个事件在 Spring Boot 应用运行开始时,且进行任何处理之前发送(除了监听器和初始化器注册之外)。
2、ApplicationEnvironmentPreparedEvent
这个事件在当已知要在上下文中使用 Spring 环境(Environment)时,在 Spring 上下文(context)创建之前发送。
3、ApplicationContextInitializedEvent
这个事件在当 Spring 应用上下文(ApplicationContext)准备好了,并且应用初始化器(ApplicationContextInitializers)已经被调用,在 bean 的定义(bean definitions)被加载之前发送。
4、ApplicationPreparedEvent
这个事件是在 Spring 上下文(context)刷新之前,且在 bean 的定义(bean definitions)被加载之后发送。
5、ApplicationStartedEvent
这个事件是在 Spring 上下文(context)刷新之后,且在 application/ command-line runners 被调用之前发送。
6、AvailabilityChangeEvent
这个事件紧随上个事件之后发送,状态:ReadinessState.CORRECT,表示应用已处于活动状态。
7、ApplicationReadyEvent
这个事件在任何 application/ command-line runners 调用之后发送。
8、AvailabilityChangeEvent
这个事件紧随上个事件之后发送,状态:ReadinessState.ACCEPTING_TRAFFIC,表示应用可以开始准备接收请求了。
9、ApplicationFailedEvent
这个事件在应用启动异常时进行发送。


上面所介绍的这些事件列表仅包括绑定到 SpringApplication 的 SpringApplicationEvents 事件,除了这些事件以外,以下事件也会在 ApplicationPreparedEvent 之后和 ApplicationStartedEvent 之前发送:

  • WebServerInitializedEvent
    这个 Web 服务器初始化事件在 WebServer 启动之后发送,对应的还有 ServletWebServerInitializedEvent(Servlet Web 服务器初始化事件)、ReactiveWebServerInitializedEvent(响应式 Web 服务器初始化事件)。
  • ContextRefreshedEvent
    这个上下文刷新事件是在 Spring 应用上下文(ApplicationContext)刷新之后发送。

自定义启动事件监听器

既然我们知道了 Spring Boot 在启动过程中的各个事件,那么我们就可以在每个环节来处理一些我们想做的事情,只需要自定义一个监听器来监听某个事件就可以了。
比如我们想在上面的第 8 步,即应用启动完成可以接收请求了,我们简单输出一个成功标识。

1、新建监听器

  1. import lombok.extern.slf4j.Slf4j;
  2. import org.springframework.boot.availability.AvailabilityChangeEvent;
  3. import org.springframework.boot.availability.ReadinessState;
  4. import org.springframework.context.ApplicationListener;
  5. /**
  6. * 来源:Java技术栈
  7. */
  8. @Slf4j
  9. public class JavastackListener implements ApplicationListener<AvailabilityChangeEvent> {
  10. @Override
  11. public void onApplicationEvent(AvailabilityChangeEvent event) {
  12. log.info("监听到事件:" + event);
  13. if (ReadinessState.ACCEPTING_TRAFFIC == event.getState()){
  14. log.info("应用启动完成,可以请求了……");
  15. }
  16. }
  17. }

新建一个自定义监听器,实现了 ApplicationListener 接口,泛型 AvailabilityChangeEvent 表示仅仅监听 AvailabilityChangeEvent 事件。
因第 8 步的事件和第 6 步的事件同名,我们可以根据事件的状态来区分到底是哪一个环节的事件 。

2、注册监听器

注册监听器有两种方式:
1、在资源目录中的 META-INF/spring.factories 文件中自动注册:

org.springframework.context.ApplicationListener=\ 
cn.javastack.springboot.features.listener.JavastackListener

2、如果是监听 Spring 应用上下文(ApplicationContext)创建之后的事件,可以直接在监听器上使用 @Component 注解即可,否则需要使用第一种方法的自动注册,因为 ApplicationContext 并未创建,这时的 Bean 是不能被加载的。

3、应用启动

下面来看下启动日志:
image.png

可以看到同时输出了第 6 步和 8 步的监听日志,但只输出第 8 步的启动完成日志,自定义监听实现成功。

总结

了解了 Spring Boot 启动过程中的各个事件及监听机制,大家可以依葫芦画瓢实现 Spring Boot 启动过程中的各个自定义操作,比如说在启动过程上实现动态注册、移除 Bean 等。
一般来说,不建议使用事件和监听器来实现比较耗时和繁重的任务,这样会影响应用程序的正常启动,考虑使用 Spring Boot 的 application/ command-line runners 来进行实现。

系统事件

SpringBoot事件监听机制 - 图2

事件名 作用
ApplicationStartingEvent 框架启动事件
ApplicationEnvironmentPreparedEvent 环境准备完毕事件
ApplicationContextInitializedEvent 上下文初始化
ApplicationPreparedEvent 上下文创建完毕,但是Bean还没有加载完毕
ApplicationStartedEvent bean 实例化完成,但是未调用 Runners接口
ApplicationReadyEvent 调用 Runners 接口完毕
ApplicationFailedEvent 启动失败事件

系统事件发生顺序:
SpringBoot事件监听机制 - 图3

3.4 监听器注册

SpringApplication 初始化的时候就进行了监听器注册

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    ......
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    ......
}

3.5 监听器事件触发机制

在springBoot 的中的执行顺序

    public ConfigurableApplicationContext run(String... args) {

        // ApplicationStartingEvent
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            // ApplicationEnvironmentPreparedEvent
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

            // 上下文加载之前ApplicationContextInitializedEvent
            // 上下文加载完成ApplicationPreparedEvent
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);

            // ApplicationStartedEvent
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            // ApplicationFailedEvent
            handleRunFailure(context, ex, exceptionReporters, listeners);
         }


        // ApplicationReadyEvent
        listeners.running(context);


        return context;
    }

starting 事件为例

public ConfigurableApplicationContext run(String... args) {
    ......
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    ......
}

进入 starting 方法,里面是遍历所有的 SpringApplicationRunListeners:

void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

SpringApplicationRunListeners 接口定义如下,可以看到申明了多个事件:

public interface SpringApplicationRunListener {

    default void starting() {}

    default void environmentPrepared(ConfigurableEnvironment environment) {}

    default void contextPrepared(ConfigurableApplicationContext context) {}

    default void contextLoaded(ConfigurableApplicationContext context) {}

    default void started(ConfigurableApplicationContext context) {}

    default void running(ConfigurableApplicationContext context) {}

    default void failed(ConfigurableApplicationContext context, Throwable exception){}

}

看下默认的实现类 EventPublishingRunListener

public class EventPublishingRunListener{
    ......
    private final SimpleApplicationEventMulticaster initialMulticaster;
    @Override
    public void starting() {
        // 调用广播器来发送事件
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    ......
}

进入 multicastEvent 方法

@Override
public void multicastEvent(ApplicationEvent event) {
    multicastEvent(event, resolveDefaultEventType(event));
}

resolveDefaultEventType 是对 event 的包装,不需要理会。

private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
    return ResolvableType.forInstance(event);
}

回到 multicastEvent 方法

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // 获得线程池
    Executor executor = getTaskExecutor();
    // getApplicationListeners --> 获得对当前event感兴趣的监听器列表
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

获得对当前 event 感兴趣的监听器列表:

protected Collection<ApplicationListener<?>> getApplicationListeners(
        ApplicationEvent event, ResolvableType eventType) {
    // 获取事件来源,这里的 source 就是 SpringApplication
    Object source = event.getSource();

    Class<?> sourceType = (source != null ? source.getClass() : null);
    ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

    // 从缓存中获取结果
    ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
    if (retriever != null) {
        return retriever.getApplicationListeners();
    }

    if (this.beanClassLoader == null ||
            (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                    (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
        // 完全同步构建和缓存ListenerRetriever
        synchronized (this.retrievalMutex) {
            retriever = this.retrieverCache.get(cacheKey);
            if (retriever != null) {
                return retriever.getApplicationListeners();
            }
            retriever = new ListenerRetriever(true);
            // 检索感兴趣的监听器
            Collection<ApplicationListener<?>> listeners =
                    retrieveApplicationListeners(eventType, sourceType, retriever);
            // 存放到缓存中
            this.retrieverCache.put(cacheKey, retriever);
            return listeners;
        }
    }
    else {
        // 无需 ListenerRetriever 缓存->无需同步
        return retrieveApplicationListeners(eventType, sourceType, null);
    }
}

检索感兴趣的监听器实现:

private Collection<ApplicationListener<?>> retrieveApplicationListeners(
        ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

    List<ApplicationListener<?>> allListeners = new ArrayList<>();
    Set<ApplicationListener<?>> listeners;
    Set<String> listenerBeans;
     // 获取默认事件监听器
    synchronized (this.retrievalMutex) {     
        // 这些监听器定义在 spring.factories 文件中
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }

    for (ApplicationListener<?> listener : listeners) {
        // 只有对当前 eventType 感兴趣的 listerer 才会添加到监听器列表中
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                retriever.applicationListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }

    // 通过 bean 名称获取监听器列表
    if (!listenerBeans.isEmpty()) {
        ConfigurableBeanFactory beanFactory = getBeanFactory();
        for (String listenerBeanName : listenerBeans) {
            try {
                if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
                    ApplicationListener<?> listener =
                            beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                    if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                        if (retriever != null) {
                            if (beanFactory.isSingleton(listenerBeanName)) {
                                retriever.applicationListeners.add(listener);
                            }
                            else {
                                retriever.applicationListenerBeans.add(listenerBeanName);
                            }
                        }
                        allListeners.add(listener);
                    }
                }
                else {
                    Object listener = beanFactory.getSingleton(listenerBeanName);
                    if (retriever != null) {
                        retriever.applicationListeners.remove(listener);
                    }
                    allListeners.remove(listener);
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
            }
        }
    }
    // 对监听器列表进行排序
    AnnotationAwareOrderComparator.sort(allListeners);
    if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
        retriever.applicationListeners.clear();
        retriever.applicationListeners.addAll(allListeners);
    }
    return allListeners;
}

获取感兴趣的事件判断逻辑

protected boolean supportsEvent(
        ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
    // 必须是 GenericApplicationListener 监听器类型,如果不是需要进行转换
    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
            (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

构建为 GenericApplicationListenerAdapter

public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
    Assert.notNull(delegate, "Delegate listener must not be null");
    this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
    this.declaredEventType = resolveDeclaredEventType(this.delegate);
}

@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
    ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
    if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
        Class<?> targetClass = AopUtils.getTargetClass(listener);
        if (targetClass != listener.getClass()) {
            declaredEventType = resolveDeclaredEventType(targetClass);
        }
    }
    return declaredEventType;
}

@Nullable
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
    ResolvableType eventType = eventTypeCache.get(listenerType);
    if (eventType == null) {
        eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
        eventTypeCache.put(listenerType, eventType);
    }
    return (eventType != ResolvableType.NONE ? eventType : null);
}

进入 GenericApplicationListenerAdapter 类 supportsEventType 和 supportsSourceType 方法

@Override
@SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
    if (this.delegate instanceof SmartApplicationListener) {
        Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
        return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
    }
    else {
        return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
    }
}    

@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
    return !(this.delegate instanceof SmartApplicationListener) ||
            ((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
}

我们回到 invokeListener 方法的实现上来:

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);
    }
}

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    try {
        // 发送事件
        listener.onApplicationEvent(event);
    } catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
            Log logger = LogFactory.getLog(getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}