之前的文章分析了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
函数
此例,了解了
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 extends SpringApplicationRunListener> 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
实现的
注意:在该包下还有EventPublishingRunListener
接口,用来发布各种事件,下面我们会详细分析
此处要注意SpringApplicationRunListeners
和SpringApplicationRunListener
的关系
-
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();
时,调用了
SpringApplicationRunListeners
的starting()
方法
//首次启动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
根据事件类型获取对应的监听器集合,细节还很多,还有很多没分析到的地方,篇幅限制,不能把所有的代码都粘贴出来,大家谅解!