引言
最近在看tomcat源碼,源碼中出現了大量事件消息,可以說整個tomcat的啟動流程都可以通過事件派發機制串起來,研究透了tomcat的各種事件消息,基本上對tomcat的啟動流程也就有了一個整體的認識。在這一基礎上,聯想到之前在看spring源碼過程中也存在不少事件相關知識,于是想對這兩個框架中的事件派發機制做一個簡單的總結,加深理解。
事件機制原理其實比較簡單,抽象來看的話,設計模式中的觀察者模式可以說是最經典的事件驅動機制的體現了,觀察者和被觀察者就體現了事件監聽和事件派發的角色。還有各種mq,其實也是事件機制的一種體現。
理解tomcat和spring中的事件機制之前,讓我們先從最基本的jdk中提供的事件機制開始說起。
jdk中的事件機制
jdk中對事件機制的各個角色提供了完善的抽象,主要包括3個角色:
eventobject(事件關注內容):事件發布時需要關注的內容。jdk中提供了eventobject接口。
eventlistener(事件監聽者):事件監聽對象,也就是對eventobject感興趣的對象。jdk中提供了eventlistener接口。
eventsource(事件源):發布事件的對象,可以在該對象中組冊eventlistener,然后在特定的條件下發布eventobject給已經注冊的eventlistener。
事件的注冊與發布,需要這三個對象協同工作,可以通過下面的例子來說明各個對象的作用:
首先是事件關注內容對象myeventobject,實現了eventobject接口。eventname參數為具體的事件關注內容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class myeventobject extends eventobject { private string eventname ; public myeventobject (object source, string eventname) { super (source); this .seteventname(eventname); } public string geteventname() { return eventname; } public void seteventname(string eventname) { this .eventname = eventname; } private static final long serialversionuid = 8374250957018011175l; } |
其次是事件監聽接口myeventlistener,繼承了eventlistener,定義了一個myevent接口用來發布事件,任何感興趣的監聽對象都可以實現該接口來監聽。
對myeventobject感興趣的監聽者myeventlistenerimpl,實現了myeventlistener接口,當事件發布時會觸發myevent事件并收到myeventobject對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public interface myeventlistener extends eventlistener { public void myevent(myeventobject eventobject); } public class myeventlistenerimpl implements myeventlistener { @override public void myevent(myeventobject eventobject) { system.out.println( "myeventlistenerimpl --- " + eventobject.geteventname()); } } |
最后是事件發布源對象myeventsource,它可以注冊多個事件監聽對象,任何實現了myeventlistener接口的監聽對象都可以注冊,內部通過一個set來存儲感興趣的監聽對象,并在合適的時機會發布消息并通知所有監聽對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class myeventsource { private set<myeventlistener> myeventlisteners = new hashset<>(); public void addlistener(myeventlistener listener){ this .myeventlisteners.add(listener); } public void removelistener(myeventlistener listener){ this .myeventlisteners.remove(listener); } public void pushevent(){ //dosomething //發布push event消息 notifylistener( new myeventobject( this , "push event" )); } private void notifylistener(myeventobject eventobject){ for (myeventlistener myeventlistener : myeventlisteners) { myeventlistener.myevent(eventobject); } } } |
之后可以通過一個啟動類來注冊并觸發事件:
1
2
3
4
5
6
7
8
9
10
|
public static void main(string[] args) { myeventsource myeventsource = new myeventsource(); myeventlistenerimpl myeventlistenerimpl = new myeventlistenerimpl(); myeventsource.addlistener(myeventlistenerimpl); myeventsource.pushevent(); } |
myeventobject定義了感興趣的內容,myeventlistenerimpl是對myeventobject感興趣的監聽者,myeventsource會發布myeventobject給所有組冊的監聽者,最后通過一個main來啟動整個流程。
明白了jdk中對事件機制的定義,再來看看tomcat和spring中的事件機制。
tomcat的事件機制
tomcat的事件機制也離不開eventobject、eventlistener以及eventsource三個對象,只不過在此基礎上提供了更加抽象和便捷的操作。這里我挑選tomcat的生命周期接口對象lifecycle來講解整個事件發布流程:
首先還是eventobject對象lifecycleevent,這里只列出了核心代碼。它的主要參數是lifecycle,lifecycle中定義了tomcat各個階段的名稱:before_init、after_init、start等等,是事件監聽者感興趣的對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public final class lifecycleevent extends eventobject { //...... public lifecycleevent(lifecycle lifecycle, string type, object data) { super (lifecycle); this .type = type; this .data = data; } //...... } public interface lifecycle { /** * the lifecycleevent type for the "component after init" event. */ public static final string before_init_event = "before_init" ; /** * the lifecycleevent type for the "component after init" event. */ public static final string after_init_event = "after_init" ; /** * the lifecycleevent type for the "component start" event. */ public static final string start_event = "start" ; //...... } |
事件監聽接口lifecyclelistener,定義了lifecycleevent方法用來傳遞監聽者感興趣的lifecycleevent對象,監聽者使用lifecycleevent參數用來在tomcat的各個階段處理進行相應處理。這些感興趣的對象包括下面這些類:
這里使用contextconfig類為例,可以看到它實現了lifecyclelistener接口。這個類在解析server.xml的時候用來監聽standardcontext的各個階段的事件,并做出相應處理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public interface lifecyclelistener { public void lifecycleevent(lifecycleevent event); } public class contextconfig implements lifecyclelistener { //...... @override public void lifecycleevent(lifecycleevent event) { // identify the context we are associated with try { context = (context) event.getlifecycle(); } catch (classcastexception e) { log.error(sm.getstring( "contextconfig.cce" , event.getlifecycle()), e); return ; } // process the event that has occurred if (event.gettype().equals(lifecycle.configure_start_event)) { configurestart(); } else if (event.gettype().equals(lifecycle.before_start_event)) { beforestart(); } else if (event.gettype().equals(lifecycle.after_start_event)) { // restore docbase for management tools if (originaldocbase != null ) { context.setdocbase(originaldocbase); } } else if (event.gettype().equals(lifecycle.configure_stop_event)) { configurestop(); } else if (event.gettype().equals(lifecycle.after_init_event)) { init(); } else if (event.gettype().equals(lifecycle.after_destroy_event)) { destroy(); } } //...... } |
lifecyclesupport是我們需要了解的主要對象,它是監聽對象的一個管理類,原理其實和上面的例子差不多,對應了myeventsource類的部分功能,方便eventsource類來管理監聽對象。它把對監聽對象的添加移除以及發布事件幾個操作進行了統一管理,避免eventsource類中出現太多管理監聽對象的邏輯。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
public final class lifecyclesupport { //...... //監聽對象集合 private lifecyclelistener listeners[] = new lifecyclelistener[ 0 ]; private final object listenerslock = new object(); // lock object for changes to listeners //添加監聽對象 public void addlifecyclelistener(lifecyclelistener listener) { synchronized (listenerslock) { lifecyclelistener results[] = new lifecyclelistener[listeners.length + 1 ]; for ( int i = 0 ; i < listeners.length; i++) results[i] = listeners[i]; results[listeners.length] = listener; listeners = results; } } //發布監聽對象 public void firelifecycleevent(string type, object data) { lifecycleevent event = new lifecycleevent(lifecycle, type, data); lifecyclelistener interested[] = listeners; for ( int i = 0 ; i < interested.length; i++) interested[i].lifecycleevent(event); } //移除監聽對象 public void removelifecyclelistener(lifecyclelistener listener) { synchronized (listenerslock) { int n = - 1 ; for ( int i = 0 ; i < listeners.length; i++) { if (listeners[i] == listener) { n = i; break ; } } if (n < 0 ) return ; lifecyclelistener results[] = new lifecyclelistener[listeners.length - 1 ]; int j = 0 ; for ( int i = 0 ; i < listeners.length; i++) { if (i != n) results[j++] = listeners[i]; } listeners = results; } } } |
使用了lifecyclesupport之后,操作lifecyclelistener就簡單多了,只需要調用lifecyclesupport的各個方法就可以了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public abstract class lifecyclebase implements lifecycle{ //...... private lifecyclesupport lifecycle = new lifecyclesupport( this ); @override public void addlifecyclelistener(lifecyclelistener listener) { lifecycle.addlifecyclelistener(listener); } @override public void removelifecyclelistener(lifecyclelistener listener) { lifecycle.removelifecyclelistener(listener); } protected void firelifecycleevent(string type, object data) { lifecycle.firelifecycleevent(type, data); } //...... } |
在需要發布事件時調用firelifecycleevent方法就可以發布事件:
1
|
firelifecycleevent(lifecycle.configure_stop_event, null ); |
tomcat事件機制就是在之前的例子上抽出了一個lifecyclesupport類來方便管理監聽對象的各種操作,這是一個可以借鑒的地方,其他差別并不大。再來看看spring中對事件機制的處理。
spring的事件機制
spring中的事件機制原理也是一樣的,只是相對來說實現上稍微復雜一點。還是通過相同的角度來看這個問題。
首先是eventobject,spring里面的主要實現是applicationevent:
這里通過contextstartedevent類來查看eventobject,它關注的對象是applicationcontext,是spring容器在啟動時觸發的事件對象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public abstract class applicationevent extends eventobject { //...... public applicationevent(object source) { super (source); this .timestamp = system.currenttimemillis(); } //...... } public abstract class applicationcontextevent extends applicationevent { public applicationcontextevent(applicationcontext source) { super (source); } public final applicationcontext getapplicationcontext() { return (applicationcontext) this .getsource(); } } public class contextstartedevent extends applicationcontextevent { public contextstartedevent(applicationcontext source) { super (source); } } |
事件監聽接口applicationlistener,定義了onapplicationevent方法用來傳遞監聽者感興趣的applicationevent對象,監聽者使用applicationevent參數用來在context的各個階段處理進行相應處理。
如果我們需要在容器啟動后進行相應處理,那么我們可以在業務類中實現applicationlistener接口,在事件發生時就會發起通知:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public interface applicationlistener<e extends applicationevent> extends eventlistener { void onapplicationevent(e event); } public class myapplicationlistener implements applicationlistener<applicationevent> { @override public void onapplicationevent(applicationevent applicationevent) { if (applicationevent instanceof contextrefreshedevent){ system.out.println( "context refresh!" ); } } } |
那么在spring框架中是怎么發布這些事件的呢?是不是也有一個類似tomcat中lifecyclesupport一樣的類呢?通過查看源碼可以發現發現,applicationcontext容器在初始化階段會調用refresh()方法,這其中又調用了
finishrefresh()方法,這其中調用了publishevent(new contextrefreshedevent(this))方法,發布了contextrefreshedevent這一對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
protected void finishrefresh() { //...... // publish the final event. publishevent( new contextrefreshedevent( this )); } protected void publishevent(object event, @nullable resolvabletype eventtype) { //...... getapplicationeventmulticaster().multicastevent(applicationevent, eventtype); //...... } publishevent方法通過調用一個默認的多播器simpleapplicationeventmulticaster的multicastevent方法來發布各種事件: simpleapplicationeventmulticaster public void multicastevent( final applicationevent event, @nullable resolvabletype eventtype) { resolvabletype type = (eventtype != null ? eventtype : resolvedefaulteventtype(event)); //通過getapplicationlisteners獲取了所有監聽器,然后通過invokelistener方法循環發布事件 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) { //...... doinvokelistener(listener, event); } private void doinvokelistener(applicationlistener listener, applicationevent event) { //...... listener.onapplicationevent(event); } |
也就是說在spring容器中發布applicationlistener所關注的對象是通過simpleapplicationeventmulticaster這個類來管理的,和tomcat中lifecyclesupport的功能類似,只是在實現上有略微差別。
最后提一句,在spring中你也可以自己發布各種事件,調用applicationcontext的publishevent方法即可。
1
|
applicationcontext.publishevent( new applicationevent( new string( "事件發布" )) { }); |
總結
這篇文章對java的事件機制在tomcat以及spring框架中的實現做了一個簡單總結和對比,你需要知道以下幾點:
- jdk中定義了eventobject和eventlistener兩個接口,奠定了事件機制的基礎。
- tomcat額外提供了一個support類來對監聽器的添加刪除以及發布進行管理。
- spring容器內部通過simpleapplicationeventmulticaster來發布各個事件,用戶可以通過實現applicationlistener接口來監聽自己感興趣的容器事件。
希望你通過這篇文章的學習可以對java的事件機制有一個更深刻的認識,在實現自己的事件機制時有可以借鑒以及改進的地方。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/konck/p/10134541.html