05--SpringBoot启动之事件监听机制

之前的文章分析了SpringBoot如何实例化SpringApplication对象,接下来分析run方法中的事件监听机制,在此之前先了解下Java的事件监听机制

1. Java的事件监听机制

Java自定义事件实现:

  • 自定义事件继承-->java.util.EventObject
  • 自定义事件监听器实现-->java.util.EventListener接口
    例:监听方法耗时

1.1 继承EventObject定义事件类型

package sample.simple.event;

import java.util.EventObject;

public class MethodMonitorEvent extends EventObject {

    public long timestamp;

    /**
     * Constructs a prototypical Event.
     *
     * @param source The object on which the Event initially occurred.
     * @throws IllegalArgumentException if source is null.
     */
    public MethodMonitorEvent(Object source) {
        super(source);
    }
}

1.2 实现EventListener接口定义监听器

package sample.simple.event;

import java.util.EventListener;

public class MethodMonitorEventListener implements EventListener {

    public void onMethodBegin(MethodMonitorEvent event) {
        // 记录方法开始执行时的时间
        System.out.println("==记录方法耗时开始");
        event.timestamp = System.currentTimeMillis();
    }

    public void onMethodEnd(MethodMonitorEvent event) {
        // 计算方法耗时
        long duration = System.currentTimeMillis() - event.timestamp;
        System.out.println("==记录方法耗时结束");
        System.out.println("==耗时:" + duration);
    }
}

1.3 发布事件并测试

package sample.simple.event;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class MethodMonitorEventPublisher {
    private List listeners = new ArrayList();


    public void methodMonitor() throws InterruptedException {
        MethodMonitorEvent eventObject = new MethodMonitorEvent(this);
        publishEvent("begin", eventObject);
        // 模拟方法执行:休眠5秒钟
        TimeUnit.SECONDS.sleep(5);
        publishEvent("end", eventObject);

    }

    private void publishEvent(String status, MethodMonitorEvent event) {
        List copyListeners = new ArrayList(listeners);
        for (MethodMonitorEventListener listener : copyListeners) {
            if ("begin".equals(status)) {
                listener.onMethodBegin(event);
            } else {
                listener.onMethodEnd(event);
            }
        }
    }

    public void addEventListener(MethodMonitorEventListener listener) {
        listeners.add(listener);
    }


    public static void main(String[] args) throws InterruptedException {
        MethodMonitorEventPublisher publisher = new MethodMonitorEventPublisher();
        publisher.addEventListener(new MethodMonitorEventListener());
        publisher.methodMonitor();
    }

}

运行main函数

image.png

此例,了解了Java的事件监听机制,并简单的实现了一个观察者模式,有助于接下来对SpringBoot事件监听机制的了解

2. SpringBoot中的事件监听机制

2.1 SpringBoot中的事件发布者

接着看run方法

//根据args获取所有SpringApplicationRunListeners监听器
SpringApplicationRunListeners listeners = getRunListeners(args);

//这段代码大家应该已经熟悉了,获取SpringApplicationRunListeners扩展
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class[] types = new Class[]{SpringApplication.class, String[].class};
    return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

以上代码通过Class[] types = new Class[]{SpringApplication.class, String[].class};类型加载对应的监听器,并创建SpringApplicationRunListener实例,看下'SpringApplicationRunListener'的构造方法

// 接受一个Log和Collection对象并赋给类成员变量
private final Log log;
private final List listeners;

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

通过分析,SpringApplicationRunListeners类的主要作用就是存储监听器对象集合并发布各种监听事件,SpringApplicationRunListeners其本质上就是一个事件对象存储和发布者,它在SpringBoot应用启动的不同时间点委托给ApplicationEventMulticaster(下面有介绍)发布不同应用事件类型(ApplicationEvent)
SpringApplicationRunListeners会发布哪些事件呢,看源码

//首次启动run方法时立即调用。
public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

// 一旦准备好环境,但在ApplicationContext创建环境之前调用 。
public void environmentPrepared(ConfigurableEnvironment environment) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.environmentPrepared(environment);
    }
}

// ApplicationContext在创建和准备之后调用,但在加载源之前调用。
public void contextPrepared(ConfigurableApplicationContext context) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.contextPrepared(context);
    }
}

// 在应用程序上下文加载之后但在刷新之前调用。
public void contextLoaded(ConfigurableApplicationContext context) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.contextLoaded(context);
    }
}

// 上下文已被刷新,并且应用程序已启动,且CommandLineRunners和ApplicationRunners未被调用。
public void started(ConfigurableApplicationContext context) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.started(context);
    }
}

// 在run方法完成之前立即调用,应用上下文已经被刷新,并且CommandLineRunners和ApplicationRunners已经被调用
public void running(ConfigurableApplicationContext context) {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.running(context);
    }
}

// 在运行应用程序时发生故障时调用。
public void failed(ConfigurableApplicationContext context, Throwable exception) {
    for (SpringApplicationRunListener listener : this.listeners) {
        callFailedListener(listener, context, exception);
    }
}
2.2 SpringBoot中的事件类型

查看org.springframework.boot.context.event包下类共定义了以下事件类型

  • ApplicationEnvironmentPreparedEvent.java
  • ApplicationFailedEvent.java
  • ApplicationPreparedEvent.java
  • ApplicationReadyEvent.java
  • ApplicationStartedEvent.java
  • ApplicationStartingEvent.java
  • SpringApplicationEvent.java
    上面类的定义和作用比较简答,可查看类注释
    SpringApplicationEvent类是SpringBoot事件类的抽象基类,查看其类图关系,可以发现,该类也是通过继承java.util.EventObject实现的
image.png

注意:在该包下还有EventPublishingRunListener接口,用来发布各种事件,下面我们会详细分析

此处要注意SpringApplicationRunListenersSpringApplicationRunListener的关系
  • SpringApplicationRunListeners中包含了private final List listeners集合
  • 真正负责事件发布的是SpringApplicationRunListener
  • SpringApplicationRunListener中又维护了SimpleApplicationEventMulticaster对象,并通过该对象将事件广播给各个监听器
2.3 SpringBoot中的事件监听器

打开spring.factories文件查看

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

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
2.4 SpringBoot中的事件注册

SpringBoot的事件,监听器,以及其发布者,事件广播器已经有所介绍,并且SpringBoot委托ApplicationEventMulticaster进行事件广播,那么,事件是何时注册到广播器的呢,通过下面的代码逐步调用,实例化EventPublishingRunListener对象时会将事件注册到广播器

//入口是SpringApplication的run方法
SpringApplicationRunListeners listeners = getRunListeners(args);
 -getRunListeners(String[] args)
  -return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    -getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args)
    -T instance = (T) BeanUtils.instantiateClass(constructor, args);

打开EventPublishingRunListener源码

public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    //创建SimpleApplicationEventMulticaster对象
    //SimpleApplicationEventMulticaster-->AbstractApplicationEventMulticaster-->ApplicationEventMulticaster
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    //从application对象中获取所有已经加载的Listener对象,循环并注册至initialMulticaster对象
    for (ApplicationListener listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}
2.5 SpringBoot中的事件发布与监听

EventPublishingRunListener作为事件的发布者已经在前面初始化,当程序执行到listeners.starting();时,调用了
SpringApplicationRunListenersstarting()方法

//首次启动run方法时立即调用。
public void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

this.listeners集合中包含了EventPublishingRunListener实例,那么这里将要调用其starting()方法

private final SimpleApplicationEventMulticaster initialMulticaster;

@Override
// 广播ApplicationStartingEvent事件
public void starting() {
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

SimpleApplicationEventMulticaster继承了AbstractApplicationEventMulticaster,其作用如下

  • 将所有事件多播到所有已注册的侦听器,将其留给侦听器以忽略他们不感​​兴趣的事件。侦听器通常instanceof 会对传入的事件对象执行相应的检查。

  • 默认情况下,在调用线程中调用所有侦听器。这允许恶意侦听器阻塞整个应用程序的危险,但增加了最小的开销。指定备用任务执行程序以使侦听器在不同的线程中执行,例如从线程池中执行。

继续跟踪源码

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

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    //getApplicationListeners(event, type)-->通过给定的事件类型,返回监听器集合
    //此处获取到的监听器有LoggingApplicationListener,
    //DelegatingApplicationListener,
    //LiquibaseServiceLocatorApplicationListener等监听器,
    //以LoggingApplicationListener为例继续debug跟踪,至于符合获取对应的监听器,放在下面分析
    for (final ApplicationListener listener : getApplicationListeners(event, type)) {
        //如果上下文中有线程池则使用线程池调用
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

//根据事件执行对应的监听器
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);
    }
}

//执行监听器
//-->本例分析的监听器为LoggingApplicationListener
//-->事件为ApplicationStartedEvent
//大家debug时要注意看自己的事件和监听器是什么,代码跟踪会进到不同的监听器中
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().getName())) {
            // Possibly a lambda-defined listener which we could not resolve the generic event type for
            // -> let's suppress the exception and just log a debug message.
            Log logger = LogFactory.getLog(getClass());
            if (logger.isDebugEnabled()) {
                logger.debug("Non-matching event type for listener: " + listener, ex);
            }
        }
        else {
            throw ex;
        }
    }
}

@Override
//-->LoggingApplicationListener类
//判断事件类型决定调用对应的事件
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationStartingEvent) {
        //-->被调用
        onApplicationStartingEvent((ApplicationStartingEvent) event);
    } else if (event instanceof ApplicationEnvironmentPreparedEvent) {
        onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
    } else if (event instanceof ApplicationPreparedEvent) {
        onApplicationPreparedEvent((ApplicationPreparedEvent) event);
    } else if (event instanceof ContextClosedEvent && ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
        onContextClosedEvent();
    } else if (event instanceof ApplicationFailedEvent) {
        onApplicationFailedEvent();
    }
}

//实例化loggingSystem并将将日志记录系统重置为限制输出。
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
    this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
    this.loggingSystem.beforeInitialize();
}

至此,已经分析了SpringBoot中的事件类型,监听器类型,事件发布与监听的过程

继续上文未完成分析

2.6 SpringBoot根据事件类型获取对应的监听器集合

上面代码中有getApplicationListeners(event, type)一句话,SpringBoot是如何根据不同的事件来获取不同的监听器呢,看源码

//返回与给定事件类型匹配的ApplicationListeners集合。不匹配的Listeners会尽早被排除在外。
protected Collection> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
    //获取事件源,并封装至ListenerCacheKey对象
    Object source = event.getSource();
    Class sourceType = (source != null ? source.getClass() : null);
    ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

    // Quick check for existing entry on ConcurrentHashMap...
    //尝试从缓存中获取事件
    ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
    if (retriever != null) {
        return retriever.getApplicationListeners();
    }
    //检查给定类在给定上下文中是否是缓存安全的,即它是由给定的ClassLoader还是由其父类加载。
    if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                    (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
        // 加锁
        synchronized (this.retrievalMutex) {
            ////抢到锁之后再做一次判断,因为有可能在前面BLOCK的时候,另一个抢到锁的线程已经设置好了缓存
            retriever = this.retrieverCache.get(cacheKey);
            if (retriever != null) {
                return retriever.getApplicationListeners();
            }
            //前面都没有能从缓存中获取到,则创建ListenerRetriever对象,
            retriever = new ListenerRetriever(true);
            //根据事件源检索对应的监听器,详解见下面
            Collection> listeners = retrieveApplicationListeners(eventType, sourceType, retriever);
            //加入到retrieverCache缓存中
            this.retrieverCache.put(cacheKey, retriever);
            //返回监听
            return listeners;
        }
    }
    else {
        // No ListenerRetriever caching -> no synchronization necessary
        return retrieveApplicationListeners(eventType, sourceType, null);
    }
}

//根据事件源检索对应的监听器,以下例分析
//eventType-->org.springframework.boot.context.event.ApplicationStartingEvent
//sourceType-->class org.springframework.boot.SpringApplication
//retriever-->Helper类,它封装一组特定的目标监听器,允许有效地检索预先过滤的监听器。
private Collection> retrieveApplicationListeners(
        ResolvableType eventType, @Nullable Class sourceType, @Nullable ListenerRetriever retriever) {

    List> allListeners = new ArrayList<>();
    Set> listeners;
    Set listenerBeans;
    synchronized (this.retrievalMutex) {
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }
    //循环上下文初始化加载的所有监听器
    for (ApplicationListener listener : listeners) {
        //判断监听器是否支持给定的事件,下面详解
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                retriever.applicationListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }
    //此段代码不知道干啥的...
    if (!listenerBeans.isEmpty()) {
        BeanFactory beanFactory = getBeanFactory();
        for (String listenerBeanName : listenerBeans) {
            try {
                Class listenerType = beanFactory.getType(listenerBeanName);
                if (listenerType == null || supportsEvent(listenerType, eventType)) {
                    ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                    if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                        if (retriever != null) {
                            retriever.applicationListenerBeans.add(listenerBeanName);
                        }
                        allListeners.add(listener);
                    }
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Singleton listener instance (without backing bean definition) disappeared -
                // probably in the middle of the destruction phase
            }
        }
    }
    //排序并返回
    AnnotationAwareOrderComparator.sort(allListeners);
    return allListeners;
}

//判断监听器是否支持给定的事件
protected boolean supportsEvent(ApplicationListener listener, ResolvableType eventType, @Nullable Class sourceType) {
    //如果监听器是GenericApplicationListener实例,则直接返回
    //否则创建GenericApplicationListenerAdapter实例
    //GenericApplicationListenerAdapter-->事件适配器
    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
            (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

至此,我们已经分析了SpringBoot根据事件类型获取对应的监听器集合,细节还很多,还有很多没分析到的地方,篇幅限制,不能把所有的代码都粘贴出来,大家谅解!

你可能感兴趣的:(05--SpringBoot启动之事件监听机制)