文/杜琪(簡書作者)
原文連結:http://www.jianshu.com/p/4f0ad3bb98f0
著作權歸作者所有,轉載請聯系作者獲得授權,并标注“簡書作者”。
自定義事件機制
給出自定義事件類型在某些應用場景下,我們希望關注特定功能的執行情況,這種功能的開始或者結束或者異常都可以看做一個事件,是以需要定義自己的事件類型。
package com.javadu.event;
import java.util.eventobject;
public class methodexecutionevent extends eventobject {
private string methodname;
public methodexecutionevent(object source) {
super(source);
}
public methodexecutionevent(object source, string methodname) {
this.methodname = methodname;
public string getmethodname() {
return methodname;
public void setmethodname(string methodname) {
}
實作針對自定義事件類的事件監聽器接口監聽器負責處理具體的事件,當某個事件發生時,監聽器也給出具體的回應。在這個例子中,監聽器會在目标方法執行開始或者執行結束時響應對應的事件并處理。
import java.util.eventlistener;
public interface methodexecutioneventlistener extends eventlistener {
void onmethodbegin(methodexecutionevent evt);
void onmethodend(methodexecutionevent evt);
eventlistener接口的作用僅僅在于“标記”,具體要提供哪些功能需要開發者自己定義,而且,還需要為自己定義的接口提供一個預設的實作類——隻有接口的話什麼也做不了。
public class simplemethodexecutioneventlistener implements methodexecutioneventlistener {
public void onmethodbegin(methodexecutionevent evt) {
string methodname = evt.getmethodname();
system.out.println("start to execute the method[" + methodname + "]");
public void onmethodend(methodexecutionevent evt) {
system.out.println("finished to execute the method[" + methodname + "]");
組合事件類和監聽器,釋出事件這個是一個測試用例,首先需要準備測試環境:事件類+監聽器;然後再釋出事件,就可以看到監聽器對事件的處理。
public class methodexecutioneventpublisher {
private list<methodexecutioneventlistener> listeners = new arraylist<methodexecutioneventlistener>();
public void addmethodexecutioneventlistener(methodexecutioneventlistener listener) {
this.listeners.add(listener);
}
public void methodtomonitor() {
methodexecutionevent event2publish = new methodexecutionevent(this, "methodtomonitor");
//釋出方法開始執行的事件
publishevent(methodexecutionstatus.begin, event2publish);
//執行實際的方法邏輯
//……
//釋出方法執行結束的事件
publishevent(methodexecutionstatus.end, event2publish);
protected void publishevent(methodexecutionstatus status, methodexecutionevent methodexecutionevent) {
list<methodexecutioneventlistener> copylisteners = new arraylist<methodexecutioneventlistener>(listeners);
for (methodexecutioneventlistener listener: copylisteners) { //釋出事件,同時調用對應的監聽器方法
if (methodexecutionstatus.begin.equals(status)) {
listener.onmethodbegin(methodexecutionevent);
} else {
listener.onmethodend(methodexecutionevent);
}
}
public void removelistener(methodexecutioneventlistener listener) {
if (this.listeners.contains(listener)) {
this.listeners.remove(listener);
public void removealllisteners() {
this.listeners.clear();
public static void main(string[] args) {
methodexecutioneventpublisher eventpublisher = new methodexecutioneventpublisher();
eventpublisher.addmethodexecutioneventlistener(new simplemethodexecutioneventlistener()); //組合事件類和監聽器
eventpublisher.methodtomonitor();//釋出事件
java se中标準的自定義事件實作就是這個樣子,涉及三個角色,即自定義事件類型、自定義的事件監聽器和自定義的事件釋出者,如下圖所示:
javase中自定義的事件結構圖
spring 的容器内事件釋出類結構
spring的applicationcontext容器内部允許以 org.springframework.context.applicationevent的形式釋出事件, 容器内注冊的org.springframework.context.applicationlistener類型的bean定義會被applicationcontext容器自動識别,它們負責監容器内釋出的所有applicationevent類型的事件。也就是說,一旦容器内釋出applicationevent及其子類型的事件,注冊到容器的applicationlistener就會對這些事件進行處理。
applicationevent:spring容器内的事件類型,繼承自java.util.eventobject,這是一個抽象類,spring提供了三個具體的實作——contextcloseevent、contextrefreshedevent和requesthandleevent。
applicationlistener: spring容器内使用的事件監聽接口,繼承自java.util.eventlistener。applicationcontext容器啟動時,會自動識别并加載eventlistener類型的bean定義,一旦容器中有applicationevent事件釋出,就會通知這些監聽器。
applicationcontext: applicationcontext容器的具體實作類在實作事件的釋出和事件監 器的注冊方面,并沒事必躬親,而是把這些活兒轉包給了一個稱作org.springframework.context.event.applicationeventmulticaster的接口。該接口定義了具體事件監器的注冊管理以及事件釋出的方法,但接口終歸是接口,還得有具體實作。applicationeventmulticaster有一抽象實作類:org.spring-framework.context.event.abstractapplicationeventmulticaster,它實作了事件監 器的管理功能。出于靈活性和擴充性考慮,事件的釋出功能則委托給了其子類。org.springframework.context.event.simpleapplicationeventmulticaster 是 spring提供的abstractapplicationeventmulticaster的一個子類實作,添加了事件釋出功能的實作。
綜上,spring容器内部事件釋出的類圖描述如下:
spring容器内部事件釋出實作類圖
應用場景
spring的applicationcontext容器内的事件釋出機制,主要用于單一容器内的簡單消息通知和處理,并不适合分布式、多程序、多容器之間的事件通知。雖然可以通過spring的remoting支援,“曲折一點”來實作較為複雜的需求,但是難免弊大于利,失大于得。其他消息機制處理較複雜場景或許更合适。是以,我們應該在合适的地點、合适的需求分析的前提下,合理地使用spring提供的applicationcontext容器内的事件釋出機制。