spring — Spring中的事件驅動機制解析
1、JAVA中的事件驅動機制
JDK不僅提供了Observable類、Observer介面支援觀察者模式,而且也提供了EventObject、EventListener介面來支援事件監聽模式。這些類都屬於java.util包下。
1.1 觀察者模式(JDK1.0 Observable和Observer)
-
被觀察者Observable,相當於事件源和事件,執行邏輯時通知observer即可觸發oberver的update,同時可傳被觀察者和引數:addObserver/deleteObserver/notifyObservers()等,具體請參考javadoc。
-
觀察者Observer,提供了觀察者需要的主要抽象:update(Observable o, Object arg),此處還提供了一種推模型(目標主動把資料通過arg推到觀察者)/拉模型(目標需要根據自己去拉資料,arg為null)。
原始碼分析:
// 觀察者,實現此介面即可
public interface Observer {
// 當被觀察的物件發生變化時候,這個方法會被呼叫
//Observable o:被觀察的物件
// Object arg:傳入的引數
void update(Observable o, Object arg);
}
// 它是一個Class
public class Observable {
// 是否變化,決定了後面是否呼叫update方法
private boolean changed = false;
// 用來存放所有`觀察自己的物件`的引用,以便逐個呼叫update方法
// 需要注意的是:1.8的jdk原始碼為Vector(執行緒安全的),有版本的原始碼是ArrayList的集合實現;
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o); //新增一個觀察者 注意呼叫的是addElement方法,新增到末尾 所以執行時是倒序執行的
public synchronized void deleteObserver(Observer o);
public synchronized void deleteObservers(); //刪除所有的觀察者
// 迴圈呼叫所有的觀察者的update方法
public void notifyObservers();
public void notifyObservers(Object arg);
public synchronized int countObservers() {
return obs.size();
}
// 修改changed的值
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
}
1.2 釋出訂閱模式(JDK1.1 EventListener和EventObject)
事件機制一般包括三個部分:EventObject,EventListener和Source。
- EventObject:事件狀態物件的基類,它封裝了事件源物件以及和事件相關的資訊。所有java的事件類都需要繼承該類
- EventListener:是一個標記介面,就是說該介面內是沒有任何方法的。所有事件監聽器都需要實現該介面。事件監聽器註冊在事件源上,當事件源的屬性或狀態改變的時候,呼叫相應監聽器內的回撥方法(自己寫)
- Source:事件源,即觸發事件的物件,他裡面必須含有監聽它的監聽器們;
缺點:對比上面的觀察者模式,監聽模式使用起來確實非常的繁瑣,且還執行緒安全問題還得自己考慮解決。
2、Spring中的事件機制
首先看一下Spring提供的事件驅動模型體系圖:
事件流程:
- Spring提供了ApplicationEventPublisher介面作為事件釋出者,ApplicationContext介面繼承了該介面,擔當著事件釋出者的角色。
- Spring提供了ApplicationEventMulticaster介面,負責管理ApplicationListener 和 真正釋出ApplicationEvent(ApplicationContext是委託給它完成的)
- ApplicationListener實現了JDK的EventListener,但它抽象出一個onApplicationEvent方法,使用更方便。
- ApplicationEvent繼承自EventObject。 它就是媒介,充當介質的作用。
- ApplicationEventPublisher最終都是委託給ApplicationEventMulticaster去完成的。當然你也可以自己去實現一個ApplicationEventMulticaster
在spring中,容器管理所有的 bean。是ApplicationEvent 驅動的,一個ApplicationEvent publish了,觀察這個事件的監聽者就會收到通知。
在IOC容器原始碼中,與EventListener有關聯的步驟
- initApplicationEventMulticaster():初始化事件多播器
- registerListeners():註冊Listener到多播器
- finishBeanFactoryInitialization(beanFactory):涉及將@EventListener轉為普通Listener
- finishRefresh():釋出容器重新整理完成事件ContextRefreshedEvent
ApplicationListener類解析:
public abstract class ApplicationEvent extends EventObject {
private static final long serialVersionUID = 7099057708183571937L;
private final long timestamp;
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public final long getTimestamp() {
return this.timestamp;
}
}
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
// 此子介面提供了泛型,和提供了統一的處理方法
void onApplicationEvent(E event);
}
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
// 這個介面是Spring4.2後提供的,可以釋出任意的事件物件(即使不是ApplicationEvent的子類了)
// 當這個物件不是一個ApplicationEvent,我們會使用PayloadApplicationEvent來包裝一下再傳送
// 比如後面會建講到的@EventListener註解標註的放 就是使用的它
void publishEvent(Object event);
}
通過Spring原始碼我們瞭解到,Spring容器重新整理的時候會發布ContextRefreshedEvent事件,因此若我們需要監聽此事件,直接寫個監聽類即可:
@Slf4j
@Component
public class ApplicationRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Object source = event.getSource();
// 此處的source就是ApplicationContext這個物件
System.out.println(source);
//容器此時已經準備好了,可以做你該做的事了~......(請注意:若存在父子容器或者多個容器情況,此方法會被執行多次,請務必注意是否冪等)
}
}
釋出事件監聽demo:
public class MyAppEvent extends ApplicationEvent {
public MyAppEvent(Object source) {
super(source);
}
}
// 寫個監聽器,然後交給容器管理即可
@Slf4j
@Component
public class MyEventListener implements ApplicationListener<MyAppEvent> {
@Override
public void onApplicationEvent(MyAppEvent event) {
Object source = event.getSource();
long timestamp = event.getTimestamp();
System.out.println(source);
System.out.println(timestamp);
//doSomething
}
}
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
// 釋出自己的事件
applicationContext.publishEvent(new MyAppEvent("this is test event"));
}
// 輸出:
this is test event
1553581974928
總結:
使用spring事件機制能很好地幫助我們消除不同業務間的耦合關係,也可以提高執行效率,應該根據業務場景靈活選擇.
相關文章
- Spring中的事件驅動模型(一)Spring事件模型
- Spring:事件驅動Spring事件
- Spring事件監聽機制原始碼解析Spring事件原始碼
- 180609-Spring之事件驅動機制的簡單使用Spring事件
- 解析Spring Boot中的事務管理機制Spring Boot
- Spring事件機制詳解Spring事件
- Tomcat與Spring中的事件機制詳解TomcatSpring事件
- 小馬哥Spring事件驅動模型Spring事件模型
- 【spring原始碼學習】spring的事件釋出監聽機制原始碼解析Spring原始碼事件
- 18.spring系列- 事件機制Spring事件
- Spring筆記(7) - Spring的事件和監聽機制Spring筆記事件
- 基於spring實現事件驅動Spring事件
- 使用 spring reactor 非同步事件驅動SpringReact非同步事件
- 深入理解Spring的事件通知機制Spring事件
- Spring5原始碼解析-Spring中的非同步事件Spring原始碼非同步事件
- Netty背後的事件驅動機制Netty事件
- Spring事件釋出與監聽機制Spring事件
- Spring 事件監聽機制及原理分析Spring事件
- 使用Spring Cloud Stream和Spring State Machine建立事件驅動的微服務案例SpringCloudMac事件微服務
- [譯]理解 Node.js 事件驅動機制Node.js事件
- spring-event-事件監聽機制實現Spring事件
- Spring5原始碼解析-Spring框架中的事件和監聽器Spring原始碼框架事件
- 帶你自定義實現Spring事件驅動模型Spring事件模型
- Spring 原始碼解析一:SpringMVC 的載入機制原始碼SpringMVC
- springCloud學習5(Spring-Cloud-Stream事件驅動)SpringGCCloud事件
- spring event機制Spring
- Spring Boot(三):Spring Boot中的事件的使用 與Spring Boot啟動流程(Event 事件 和 Listeners監聽器)Spring Boot事件
- 聊聊Spring中的那些擴充套件機制Spring套件
- Spring 中的 XML schema 擴充套件機制SpringXML套件
- 基於Spring中的事務管理機制Spring
- Spring 原始碼(8)Spring BeanPostProcessor的註冊、國際化及事件釋出機制Spring原始碼Bean事件
- 使用Spring Cloud Stream和RabbitMQ實現事件驅動的微服務SpringCloudMQ事件微服務
- Reactor: Spring釋出基於JVM的非同步事件驅動框架ReactSpringJVM非同步事件框架
- “訊息驅動、事件驅動、流 ”基礎概念解析事件
- Redis 中的事件驅動模型Redis事件模型
- vue原始碼解析-事件機制Vue原始碼事件
- Spring AOP 的實現機制Spring
- Spring的Factories機制介紹Spring