在spring boot的启动的源码中,可以在很多个地方看到事件的应用。第三方插件与spring整合时也经常会借助事件来进行相关的初始化工作。事件的使用在启动中占有非常核心的地位。下面我们就透过源码来分析一下Spring Boot中是如何实现事件机制的。
看这个之前如果不了解事件设计模式的。可以先去看一下事件模式的原理!
实现的大致流程如下:
再来看一下在spring boot启动时是如何使用事件的
public ConfigurableApplicationContext run(String... args) {
...
//初始化事件调用工具类
SpringApplicationRunListeners listeners = getRunListeners(args);
//发布spring boot正在启动事件
listeners.starting();
try {
...
//发布Spring boot应用已经启动完成事件
listeners.started(context);
...
}
catch (Throwable ex) {...}
try {
//发布Spring Boot正在启动事件
listeners.running(context);
}catch (Throwable ex) { ... }
return context;
}
/**
* 使用SpringFactoriesLoader加载配置中的SpringApplicationRunListener的所有的实现类
*/
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
可以看到,在应用启动的时候,会在启动不同阶段发布相应的事件。先看一下调用类SpringApplicationRunListeners 的源码实现逻辑:
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
void contextPrepared(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextPrepared(context);
}
}
void contextLoaded(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.contextLoaded(context);
}
}
void started(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.started(context);
}
}
void running(ConfigurableApplicationContext context) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.running(context);
}
}
void failed(ConfigurableApplicationContext context, Throwable exception) {
for (SpringApplicationRunListener listener : this.listeners) {
callFailedListener(listener, context, exception);
}
}
private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
Throwable exception) {
try {
listener.failed(context, exception);
}
catch (Throwable ex) {
if (exception == null) {
ReflectionUtils.rethrowRuntimeException(ex);
}
if (this.log.isDebugEnabled()) {
this.log.error("Error handling failed", ex);
}
else {
String message = ex.getMessage();
message = (message != null) ? message : "no error message";
this.log.warn("Error handling failed (" + message + ")");
}
}
}
}
可以看到这个类主要是管理SpringApplicationRunListener ,执行SpringApplicationRunListener中的逻辑。
由此可见,发布时间的核心逻辑在SpringApplicationRunListener的实现类中,在看一下它的实现类
在当前版本2.2.6.RELEASE中,只有一个实现类EventPublishingRunListener 。因此直接分析这个类的源码:
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
/**
* Spring Boot 启动工具类
*/
private final SpringApplication application;
private final String[] args;
/**
* 事件广播器 ,这才是发布事件的核心类
*/
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
// 关键地方: 从SpringApplication获取其在构造时加载的ApplicationListener实例。添加到事件广播器中。
for (ApplicationListener<?> listener : application.getListeners()) {
//将SpringApplication初始化加载的Listener实例全部存入SimpleApplicationEventMulticaster的defaultRetriever中
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster
.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
private static class LoggingErrorHandler implements ErrorHandler {
private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);
@Override
public void handleError(Throwable throwable) {
logger.warn("Error calling ApplicationEventListener", throwable);
}
}
}
注意:
1 EventPublishingRunListener中包了一个SpringApplication对象实例。这个对象在初始化的时候会使用SpringFactoriesLoader去加载配置好的ApplicationListener的实现类
2 EventPublishingRunListener中包了一个SimpleApplicationEventMulticaster(发布事件的最终实现,简称SAEM)对象,在SAEM初始化之后,会从SpringApplication实例中获取所有的ApplicationListener实现类的实例注入到SAEM中的defaultRetriever中
到这里就可以看到事件模式中的三个核心对象的实现:
- 事件广播者 SimpleApplicationEventMulticaster
- 事件 SpringApplicationEvent
- 事件监听器 ApplicationListener
下面来分析一下SimpleApplicationEventMulticaster :
发布事件的核心逻辑如下:
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//获取事件类型,根据这个去刚才添加的ApplicationListener集合中查询对应的实现类
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//获取线程池
Executor executor = getTaskExecutor();
//通过事件和事件类型来获取对应的ApplicationListener实例。
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//如果设置了线程池,就用线程池使用新线程执行当前监听器的逻辑
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//如果没有设置线程池,就在当前线程中执行监听器的逻辑
invokeListener(listener, event);
}
}
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
再看事件SpringApplicationEvent的实现逻辑:
可以看到这里事件的定义和SpringApplicationRunListener接口中的方法的定义是惊人的相似。
也就是说,在spring boot应用启动的流程里会依次调用这7个事件:
- ApplicationStartingEvent
- ApplicationEnvironmentPreparedEvent
- ApplicationContextInitializedEvent .
- ApplicationPreparedEvent
- ApplicationStartedEvent
- ApplicationReadyEvent
- ApplicationFailedEvent
再来看一下监听器的实现,就以LoggingApplicationListener为例,如下
在GenericApplicationListener和SmartApplicationListener接口中有两个方法,将会在Event和Listener之间的匹配起到核心作用
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
/**
* Determine whether this listener actually supports the given event type.
* 判断这个监听器是否支持给定的时间类型
* @param eventType the event type (never {@code null})
*/
boolean supportsEventType(ResolvableType eventType);
/**
* Determine whether this listener actually supports the given source type.
* 判断这个事件是否支持给定的源类型
* <p>The default implementation always returns {@code true}.
* @param sourceType the source type, or {@code null} if no source
*/
default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}
/**
* Determine this listener's order in a set of listeners for the same event.
* <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
*/
@Override
default int getOrder() {
return LOWEST_PRECEDENCE;
}
}
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
/**
* Determine whether this listener actually supports the given event type.
* @param eventType the event type (never {@code null})
*/
boolean supportsEventType(Class<? extends ApplicationEvent> eventType);
/**
* Determine whether this listener actually supports the given source type.
* <p>The default implementation always returns {@code true}.
* @param sourceType the source type, or {@code null} if no source
*/
default boolean supportsSourceType(@Nullable Class<?> sourceType) {
return true;
}
/**
* Determine this listener's order in a set of listeners for the same event.
* <p>The default implementation returns {@link #LOWEST_PRECEDENCE}.
*/
@Override
default int getOrder() {
return LOWEST_PRECEDENCE;
}
}
只有当这个两个方法同时返回true时,Event和Listener才匹配成功
这里问题来了,怎样通过SpringApplicationEvent实例去找到对应的ApplicationListener实例呢,它们之间关联逻辑是怎样实现的?
先看一下ApplicationContextInitializedEvent事件的结构(其他的事件与此类似):
可以看到只有一个构造函数,初始化时必须传入三个参数,分别是
- SpringApplication实例 ,会通过构造函数设置到顶级父类EventObject的source属性中
- ApplicationContext实例
- main方法启动传参args[]
在发布事件时是这样调用的:
// 发布事件
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
可以看到这里面又有一个重要对象ResolvableType ,它是通过SpringApplicationEvent事件实例去构造的 。这是一个包装类型,封装了Java对象原生的一些方法。
而根据事件实例匹配对应的事件监听器的逻辑都在AbstractApplicationEventMulticaster的getApplicationListeners(ApplicationEvent event, ResolvableType eventType)中实现。这里也加了内存缓存。就不在赘述了。还是直接撸AbstractApplicationEventMulticaster源码:
在根据ApplicationEvent匹配到对应的监听器实现集合时,会以ListenerCacheKey对象作为key,ListenerRetriever 为value存在本地的内存缓存中。
ListenerCacheKey 监听器缓存key
ListenerRetriever 监听器集合包装类。
//默认的事件监听器集合包装类 ,
//在SimpleApplicationEventMulticaster初始化后,会将SpringApplication对象中的所有的Listener实例存入到defaultRetriever中
//因此defaultRetriever包含了所有的监听器
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
//监听器缓存,key=以事件类型和source构造的ListenerCacheKey对象,值为ListenerRetriever实例
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
//同步锁
private Object retrievalMutex = this.defaultRetriever;
/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @param eventType the event type
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
//获取事件源,就是初始化事件中传递的SpringApplication对象实例。
Object source = event.getSource();
//sourceType = SpringApplication.class
Class<?> sourceType = (source != null ? source.getClass() : null);
//构建一个缓存key ,
//参数eventType = SpringApplicationEvent事件的包装类ResolvableType实例
//参数sourceType = SpringApplication.class
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Quick check for existing entry on ConcurrentHashMap...
//从缓存中获取对应事件的Listener集合,如果没有缓存则retriever = null
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)) )
) {
// Fully synchronized building and caching of a ListenerRetriever
//再以同步的方式去缓存中取
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
//如果缓存中有则还是使用缓存
if (retriever != null) {
return retriever.getApplicationListeners();
}
//缓存没有的话就新增一个空的ListenerRetriever对象用来存放想匹配的Listener实例
retriever = new ListenerRetriever(true);
//retrieveApplicationListeners方法是最终匹配事件和事件监听器的逻辑
Collection<ApplicationListener<?>> listeners =retrieveApplicationListeners(eventType, sourceType, retriever);
//匹配到合适的监听器集合后,就存入缓存。
this.retrieverCache.put(cacheKey, retriever);
//返回结果
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
下面来分析事件与事件监听器的匹配的核心逻辑代码retrieveApplicationListeners(ResolvableType,sourceType,ListenerRetriever )
/**
* Actually retrieve the application listeners for the given event and source type.
* @param eventType the event type
* @param sourceType the event source type
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
* @return the pre-filtered list of application listeners for the given event and source type
*/
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) {
//将所有的Listenner取出来存入Set集合中
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
//遍历所有的监听器,通过时间类型来找到对应的监听器
for (ApplicationListener<?> listener : listeners) {
// Determine whether the given listener supports the given event.
//事件和监听器的核心匹配逻辑,根据listener的内部定义来判断是否触发
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
//将匹配到的listener存入ListenerRetriever容器
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
// Add listeners by bean name, potentially overlapping with programmatically
// registered listeners above - but here potentially with additional metadata.
//如果listenerBeans不等空的就到spring的context中加载对应的类,这里初始化EventPublishingRunListener 的时候没有赋值,因此在此处的listenerBeans.isEmpty()=true
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 {
// Remove non-matching listeners that originally came from
// ApplicationListenerDetector, possibly ruled out by additional
// BeanDefinition metadata (e.g. factory method generics) above.
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
从上面可以看到。事件匹配监听器时是通过supportsEvent(listener, eventType, sourceType)方法来实现。而这三个参数分别是:
- 监听器
- 事件类型
- 事件源类型
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
//判断监听器是否是GenericApplicationListener的子类
// 如果时,就强制转换为GenericApplicationListener
// 如果不是就构建一个GenericApplicationListener的适配器
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
//调用listener的supportsEventType和supportsSourceType方法
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
综上,也就是说核心的匹配逻辑是在事件监听器中实现的 , 下面来看LoggingApplicationListener的具体实现:
public class LoggingApplicationListener implements GenericApplicationListener {
private static final Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ContextClosedEvent.class,ApplicationFailedEvent.class };
private static final Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class };
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
//判断事件类型是否是EVENT_TYPES定义的事件的本身或者子类
return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
//判断事件源是不是SOURCE_TYPES类定义的子类或者本身
return isAssignableFrom(sourceType, SOURCE_TYPES);
}
private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
if (type != null) {
for (Class<?> supportedType : supportedTypes) {
if (supportedType.isAssignableFrom(type)) {
return true;
}
}
}
return false;
}
}
可以看到,匹配的核心逻辑在EVENT_TYPES ,SOURCE_TYPES 的定义里面。到此spring的事件的核心逻辑面纱就彻底揭开了。