开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
前言
在学习Spring的过程中,一定是一个漫长且又艰难的过程,因为我们所有技术的沿用的框架大差不差都是基于Spring的延伸,其底层都是基于Spring的各种机制,所以学习Spring一定要有耐心,看一遍不懂,就看两遍,两遍不懂就往三四遍看,并且自己去记录学习笔记,无论是本地记录还是同步到博客上,我都觉得是一种进步,我最近也正在进行Spring的学习,废话不多说,让我们来看看Spring事件机制具体是怎么实现的。
Spring事件机制
关于事件机制主要分为三部分,首先是是定义事件、然后进行发布事件、在对发布的事件进行监听,获取到事件发布的消息。
定义事件
ApplicationEvent,该类属于spring-context,jar包下的定义事件的抽象基类,如果想自定义事件,只需继承这个基类即可。
发布事件
ApplicationEventPublisher 紧接着看这个接口,看接口名可以知道是推送事件的。
默认的publishEvent方法,入参是一个ApplicationEvent对象,要发送的也就是定义的这个事件。
根据代码的追踪,找到了onApplicationEvent方法,看到了Spring常用的ApplicationContext初始化上下文的方法,发送事件是依靠ApplicationContext初始化上下文的方式。
所有需要发布的事件ApplicationEvent,都存放在ConcurrentLinkedQueue 线 程安全非阻塞队列里,入列的方式也是遵循先进先出。
监听事件
通过代码追踪找到了publishEvent的实现方法,看代码也是将applicationEvent事件存放在set集合里
taskExecutor异步处理
这里看到如果集合里面的事件不为空,就会交给ApplicationEventMulticaster类处理,既然是事件的监听必然离不开Listener,multicastEvent方法将接收到的事件,通过泛型的方式接收事件类型。
这里可以看创建了Executor线程池,如果线程池存在通过线程池异步去监听事件,反之则是同步监听事件。
最后调用监听器的onApplicationEvent方法进行处理
关于监听器是如何匹配事件的,我们接着看 getApplicationListeners这个方法入参为(event,type), retrieveApplicationListeners核心方法,跟踪进去会看到supportsEvent方法,先去 匹配监听器类型 , 再去判断监听器是否匹配对应的事件类型 。
//以上代码省略
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
//retrieveApplicationListeners方法
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
//supportsEvent 方法
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
AbstractApplicationContext
前面说到ApplicaitonContext去初始化ApplicaitonEvent事件,后面说到ApplicationListener监听发送的事件,现在看refresh方法,也是整个事件从初始化、注册、发布核心的方法,监听器的注册就是发生在registerListeners方法里面。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新上下文
prepareRefresh();
// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备在此上下文中使用的bean工厂。
prepareBeanFactory(beanFactory);
try {
// 允许在上下文中对bean工厂进行后处理
postProcessBeanFactory(beanFactory);
// 调用在上下文中作为bean注册的工厂处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);
// 初始化此上下文的消息源。
initMessageSource();
// 为此上下文初始化事件多播程序。
initApplicationEventMulticaster();
// 初始化特定上下文子类中的其他特殊bean。
onRefresh();
// 检查监听器bean并注册它们。
registerListeners();
// 实例化所有剩余的(非lazy-init)单例。
finishBeanFactoryInitialization(beanFactory);
// 发布相应的事件。
finishRefresh();
}
总结
Spring的Event事件机制,在很多场景都会有体现,包括注册中心的热部署、发布—订阅模式的实现等…并且支持异步和同步的方式对事件进行监听,也可以通过注解的方式@EventListener对定义的事件进行监听。