事件驅動模型簡介
事件驅動模型通常也被理解成觀察者或者釋出/訂閱模型。
- 是一種物件間的一對多的關係;
- 當目標傳送改變(釋出),觀察者(訂閱者)就可以接收到改變;
- 觀察者如何處理,目標無需干涉,它們之間的關係是鬆耦合的。
事件驅動模型的例子很多,如生活中的紅綠燈,以及我們在微服務中用到的配置中心,當有配置提交時出發具體的應用例項更新Spring上下文環境。
Spring的事件機制
基本概念
Spring的事件驅動模型由三部分組成:
- 事件:ApplicationEvent,繼承自JDK的EventObject,所有事件將繼承它,並通過source得到事件源。
- 事件釋出者:ApplicationEventPublisher及ApplicationEventMulticaster介面,使用這個介面,我們的Service就擁有了釋出事件的能力。
- 事件訂閱者:ApplicationListener,繼承自JDK的EventListener,所有監聽器將繼承它。
Spring事件驅動過程
事件
Spring 預設對 ApplicationEvent 事件提供瞭如下實現:
- ContextStoppedEvent:ApplicationContext停止後觸發的事件;
- ContextRefreshedEvent:ApplicationContext初始化或重新整理完成後觸發的事件;
- ContextClosedEvent:ApplicationContext關閉後觸發的事件。如web容器關閉時自動會觸發Spring容器的關閉,如果是普通java應用,需要呼叫
ctx.registerShutdownHook()
註冊虛擬機器關閉時的鉤子才行; - ContextStartedEvent:ApplicationContext啟動後觸發的事件;
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
//事件發生的時間
private final long timestamp = System.currentTimeMillis();
//建立一個新的ApplicationEvent事件
public ApplicationEvent(Object source) {
super(source);
}
public final long getTimestamp() {
return this.timestamp;
}
}
複製程式碼
事件基類ApplicationEvent
,所有的具體事件都會繼承該抽象事件類。
事件監聽者
ApplicationListener
繼承自JDK的EventListener
,JDK要求所有監聽器將繼承它。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E var1);
}
複製程式碼
提供了onApplicationEvent方法,用以處理ApplicationEvent
,不過對於具體事件的處理需要進行判斷。而GenericApplicationListener
和SmartApplicationListener
提供了關於事件更多的後設資料資訊。
public class SourceFilteringListener implements GenericApplicationListener, SmartApplicationListener {
private final Object source;
@Nullable
private GenericApplicationListener delegate;
//為特定事件源建立SourceFilteringListener,並傳入代理的監聽器類
public SourceFilteringListener(Object source, ApplicationListener<?> delegate) {
this.source = source;
this.delegate = (delegate instanceof GenericApplicationListener ?
(GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
}
//....省略部分程式碼
@Override
public int getOrder() {
return (this.delegate != null ? this.delegate.getOrder() : Ordered.LOWEST_PRECEDENCE);
}
//過濾之後實際處理事件
protected void onApplicationEventInternal(ApplicationEvent event) {
//...
this.delegate.onApplicationEvent(event);
}
}
複製程式碼
SourceFilteringListener
是ApplicationListener
的裝飾器類,過濾特定的事件源。只會注入其事件對應的代理監聽器,還提供了按照順序觸發監聽器等功能。
在啟動的時候會載入一部分 ApplicationListener
。Spring Context載入初始化完成(refresh)後會再次檢測應用中的 ApplicationListener
,並且註冊,此時會將我們實現的 ApplicationListener
就會加入到 SimpleApplicationEventMulticaster
維護的 Listener 集合中。
Spring也支援直接註解的形式進行事件監聽@EventListener(Event.class)
。
事件釋出
ApplicationContext
介面繼承了ApplicationEventPublisher
,並在AbstractApplicationContext
實現了具體程式碼,實際執行是委託給ApplicationEventMulticaster
。
@FunctionalInterface
public interface ApplicationEventPublisher {
//通知所有的註冊該事件的應用,事件可以是框架事件如RequestHandledEvent或者特定的應用事件。
default void publishEvent(ApplicationEvent event) {
this.publishEvent((Object)event);
}
void publishEvent(Object var1);
}
複製程式碼
實際的執行是委託給,讀者有興趣可以看一下AbstractApplicationContext
中這部分的邏輯。下面我們具體看一下ApplicationEventMulticaster
介面中定義的方法。
public interface ApplicationEventMulticaster {
//增加監聽者
void addApplicationListener(ApplicationListener<?> listener);
//...
//移除監聽者
void removeApplicationListener(ApplicationListener<?> listener);
//...
//廣播特定事件給監聽者
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
複製程式碼
AbstractApplicationContext
中定義了對監聽者的操作維護,如增加和刪除,並提供了將特定事件進行廣播的方法。下面看一下具體實現類SimpleApplicationEventMulticaster
。ApplicationContext
自動到本地容器裡找一個ApplicationEventMulticaster
實現,如果沒有則會使用預設的SimpleApplicationEventMulticaster
。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Nullable
private Executor taskExecutor;
//...
//用給定的beanFactory建立SimpleApplicationEventMulticaster
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
setBeanFactory(beanFactory);
}
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
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);
}
...
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
//...
}
}
複製程式碼
在multicastEvent
方法中,executor不為空的情況下,可以看到是支援非同步釋出事件。釋出事件時只需要呼叫ApplicationContext
中的publishEvent
方法即可進行事件的釋出。
總結
本文主要介紹了Spring中的事件驅動模型相關概念。首先介紹事件驅動模型,也可以說是觀察者模式,在我們的日常生活中和應用開發中有很多應用。隨後重點篇幅介紹了Spring的事件機制,Spring的事件驅動模型由事件、釋出者和訂閱者三部分組成,結合Spring的原始碼分析了這三部分的定義與實現。筆者將會在下一篇文章,結合具體例子以及Spring Cloud Config中的實現進行實戰講解。