先扯再說
最近一直在研究某個國產(chǎn)開源的MySQL數(shù)據(jù)庫中間件,拉下其最新版的代碼到eclipse后,啟動起來,然后做各種測試和代碼追蹤;用完想要關閉它時,拉出它的STOP類想要運行時,發(fā)現(xiàn)這個類里赫然只寫以下幾行代碼,于是我感覺瞬間受到了很多傷害。
1
2
3
|
public static void main(String[] args) { System.out.println( new Date() + ",server shutdown!" ); } |
這個中間件啟動和運行的時候,開啟了監(jiān)聽,啟動著許多線程在跑著,并且有許多socket連接。但是并沒有找到一個優(yōu)雅的方式將其關閉。于是無奈之下,我只能去點eclipse的心碎小紅點,強行停掉VM。
如果是一個架構良好,模塊化清晰的軟件,特別是Server類的軟件,擁有一套生命周期管理機制是非常重要的。不僅可以管理各個模塊的生命周期,也可以在啟停整個軟件的時候更優(yōu)雅,不會漏掉任何資源。
生命周期機制簡易實現(xiàn)
生命周期狀態(tài)
一個模塊的生命周期狀態(tài)一般有以下幾個:
新生 -> 初始化中 -> 初始化完成 -> 啟動中 -> 啟動完成 -> 正在暫停 -> 已經(jīng)暫停 -> 正在恢復 -> 已經(jīng)恢復 -> 正在銷毀 -> 已經(jīng)銷毀
其中,任何一個狀態(tài)之間的轉化如果失敗,那么就會進入另外一種狀態(tài):失敗。
為此,可以用一個枚舉類來枚舉出這幾個狀態(tài),如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public enum LifecycleState { NEW, //新生 INITIALIZING, INITIALIZED, //初始化 STARTING, STARTED, //啟動 SUSPENDING, SUSPENDED, //暫停 RESUMING, RESUMED, //恢復 DESTROYING, DESTROYED, //銷毀 FAILED; //失敗 } |
接口
生命周期中的各種行為規(guī)范,也需要一個接口來定義,如下所示:
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
|
public interface ILifecycle { /** * 初始化 * * @throws LifecycleException */ public void init() throws LifecycleException; /** * 啟動 * * @throws LifecycleException */ public void start() throws LifecycleException; /** * 暫停 * * @throws LifecycleException */ public void suspend() throws LifecycleException; /** * 恢復 * * @throws LifecycleException */ public void resume() throws LifecycleException; /** * 銷毀 * * @throws LifecycleException */ public void destroy() throws LifecycleException; /** * 添加生命周期監(jiān)聽器 * * @param listener */ public void addLifecycleListener(ILifecycleListener listener); /** * 刪除生命周期監(jiān)聽器 * * @param listener */ public void removeLifecycleListener(ILifecycleListener listener); } |
發(fā)生生命周期狀態(tài)轉化時,可能需要觸發(fā)對某類事件感興趣的監(jiān)聽者,因此ILifeCycle也定義了兩個方法可以添加和移除監(jiān)聽者。分別是:public void addLifecycleListener(ILifecycleListener listener);和 public void removeLifecycleListener(ILifecycleListener listener);
監(jiān)聽者也由一個接口來定義其行為規(guī)范,如下所示:
1
2
3
4
5
6
7
8
9
|
public interface ILifecycleListener { /** * 對生命周期事件進行處理 * * @param event 生命周期事件 */ public void lifecycleEvent(LifecycleEvent event); } |
生命周期事件由LifecycleEvent來表示,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public final class LifecycleEvent { private LifecycleState state; public LifecycleEvent(LifecycleState state) { this .state = state; } /** * @return the state */ public LifecycleState getState() { return state; } } |
骨架實現(xiàn)
有了ILifeCycle接口以后,任何實現(xiàn)了這個接口的類將會被作為一個生命周期管理對象,這個類可以是一個socket監(jiān)聽服務,也可以代表一個特定的模塊,等等。那我們是不是只要實現(xiàn)ILifeCycle就可以了? 可以這么說,但考慮到各個生命周期管理對象在生命周期的各個階段會有一些共同的行為,比如說:
設置自身的生命周期狀態(tài)
檢查狀態(tài)的轉換是否符合邏輯
通知監(jiān)聽者生命周期狀態(tài)發(fā)生了變化
因此,提供一個抽象類AbstractLifeCycle,作為ILifeCycle的骨架實現(xiàn)是有重要意義的,這樣避免了很多的重復代碼,使得架構更加清晰。這個抽象類會實現(xiàn)ILifeCycle中定義的所有接口方法,并添加對應的抽象方法,供子類實現(xiàn)。AbstractLifeCycle可以這么實現(xiàn):
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
public abstract class AbstractLifecycle implements ILifecycle { private List<ILifecycleListener> listeners = new CopyOnWriteArrayList<ILifecycleListener>(); /** * state 代表當前生命周期狀態(tài) */ private LifecycleState state = LifecycleState.NEW; /* * @see ILifecycle#init() */ @Override public final synchronized void init() throws LifecycleException { if (state != LifecycleState.NEW) { return; } setStateAndFireEvent(LifecycleState.INITIALIZING); try { init0(); } catch (Throwable t) { setStateAndFireEvent(LifecycleState.FAILED); if (t instanceof LifecycleException) { throw (LifecycleException) t; } else { throw new LifecycleException(formatString( "Failed to initialize {0}, Error Msg: {1}", toString(), t.getMessage()), t); } } setStateAndFireEvent(LifecycleState.INITIALIZED); } protected abstract void init0() throws LifecycleException; /* * @see ILifecycle#start() */ @Override public final synchronized void start() throws LifecycleException { if (state == LifecycleState.NEW) { init(); } if (state != LifecycleState.INITIALIZED) { return; } setStateAndFireEvent(LifecycleState.STARTING); try { start0(); } catch (Throwable t) { setStateAndFireEvent(LifecycleState.FAILED); if (t instanceof LifecycleException) { throw (LifecycleException) t; } else { throw new LifecycleException(formatString("Failed to start {0}, Error Msg: {1}", toString(), t.getMessage()), t); } } setStateAndFireEvent(LifecycleState.STARTED); } protected abstract void start0() throws LifecycleException; /* * @see ILifecycle#suspend() */ @Override public final synchronized void suspend() throws LifecycleException { if (state == LifecycleState.SUSPENDING || state == LifecycleState.SUSPENDED) { return; } if (state != LifecycleState.STARTED) { return; } setStateAndFireEvent(LifecycleState.SUSPENDING); try { suspend0(); } catch (Throwable t) { setStateAndFireEvent(LifecycleState.FAILED); if (t instanceof LifecycleException) { throw (LifecycleException) t; } else { throw new LifecycleException(formatString("Failed to suspend {0}, Error Msg: {1}", toString(), t.getMessage()), t); } } setStateAndFireEvent(LifecycleState.SUSPENDED); } protected abstract void suspend0() throws LifecycleException; /* * @see ILifecycle#resume() */ @Override public final synchronized void resume() throws LifecycleException { if (state != LifecycleState.SUSPENDED) { return; } setStateAndFireEvent(LifecycleState.RESUMING); try { resume0(); } catch (Throwable t) { setStateAndFireEvent(LifecycleState.FAILED); if (t instanceof LifecycleException) { throw (LifecycleException) t; } else { throw new LifecycleException(formatString("Failed to resume {0}, Error Msg: {1}", toString(), t.getMessage()), t); } } setStateAndFireEvent(LifecycleState.RESUMED); } protected abstract void resume0() throws LifecycleException; /* * @see ILifecycle#destroy() */ @Override public final synchronized void destroy() throws LifecycleException { if (state == LifecycleState.DESTROYING || state == LifecycleState.DESTROYED) { return; } setStateAndFireEvent(LifecycleState.DESTROYING); try { destroy0(); } catch (Throwable t) { setStateAndFireEvent(LifecycleState.FAILED); if (t instanceof LifecycleException) { throw (LifecycleException) t; } else { throw new LifecycleException(formatString("Failed to destroy {0}, Error Msg: {1}", toString(), t.getMessage()), t); } } setStateAndFireEvent(LifecycleState.DESTROYED); } protected abstract void destroy0() throws LifecycleException; /* * @see * ILifecycle#addLifecycleListener(ILifecycleListener) */ @Override public void addLifecycleListener(ILifecycleListener listener) { listeners.add(listener); } /* * @see * ILifecycle#removeLifecycleListener(ILifecycleListener) */ @Override public void removeLifecycleListener(ILifecycleListener listener) { listeners.remove(listener); } private void fireLifecycleEvent(LifecycleEvent event) { for (Iterator<ILifecycleListener> it = listeners.iterator(); it.hasNext();) { ILifecycleListener listener = it.next(); listener.lifecycleEvent(event); } } protected synchronized LifecycleState getState() { return state; } private synchronized void setStateAndFireEvent(LifecycleState newState) throws LifecycleException { state = newState; fireLifecycleEvent(new LifecycleEvent(state)); } private String formatString(String pattern, Object... arguments) { return MessageFormat.format(pattern, arguments); } /* * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getSimpleName(); } } |
可以看到,抽象類的骨架實現(xiàn)中做了幾件生命周期管理中通用的事情,檢查狀態(tài)之間的轉換是否合法(比如說start之前必須要init),設置內(nèi)部狀態(tài),以及觸發(fā)相應的監(jiān)聽者。
抽象類實現(xiàn)了ILifeCycle定義的方法后,又留出了相應的抽象方法供其子類實現(xiàn),如上面的代碼所示,其留出來的抽象方法有以下這些:
1
2
3
4
5
|
protected abstract void init0() throws LifecycleException; protected abstract void start0() throws LifecycleException; protected abstract void suspend0() throws LifecycleException; protected abstract void resume0() throws LifecycleException; protected abstract void destroy0() throws LifecycleException; |
優(yōu)雅的實現(xiàn)
到目前為止,我們已經(jīng)定義了接口ILifeCycle,以及其骨架實現(xiàn)AbstractLifeCycle,并且增加了監(jiān)聽者機制。貌似我們可以開始寫一個類來繼承AbstractLifecycle,并重寫其定義的抽象方法了,so far so good。
但在開始之前,我們還需要考慮另外幾個問題,
我們的實現(xiàn)類是否對所有的抽象方法都感興趣?
是否每個實現(xiàn)累都需要實現(xiàn)init0, start0, suspend0, resume0, destroy0?
是否有時候,我們的那些有生命的類或者模塊并不支持暫停(suspend),恢復(resume)?
直接繼承AbstractLifeCycle,就意味著必須實現(xiàn)其全部的抽象方法。
因此,我們還需要一個默認實現(xiàn),DefaultLifeCycle,讓它繼承AbstractLifeCycle,并實現(xiàn)所有抽象方法,但它并不做任何實際的事情, do nothing。只是讓我們真正的實現(xiàn)類來繼承這個默認的實現(xiàn)類,并重寫感興趣的方法。
于是,我們的DefaultLifeCycle就這么誕生了:
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
|
public class DefaultLifecycle extends AbstractLifecycle { /* * @see AbstractLifecycle#init0() */ @Override protected void init0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#start0() */ @Override protected void start0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#suspend0() */ @Override protected void suspendInternal() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#resume0() */ @Override protected void resume0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#destroy0() */ @Override protected void destroy0() throws LifecycleException { // do nothing } } |
對于DefaultLifeCycle來說,do nothing就是其職責。
因此接下來我們可以寫一個自己的實現(xiàn)類,繼承DefaultLifeCycle,并重寫那些感興趣的生命周期方法。
例如,我有一個類只需要在初始化,啟動,和銷毀時做一些任務,那么可以這么寫:
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
58
59
60
|
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class SocketServer extends DefaultLifecycle { private ServerSocket acceptor = null ; private int port = 9527 ; /* * @see DefaultLifecycle#init0() */ @Override protected void init0() throws LifecycleException { try { acceptor = new ServerSocket(port); } catch (IOException e) { throw new LifecycleException(e); } } /* * @see DefaultLifecycle#start0() */ @Override protected void start0() throws LifecycleException { Socket socket = null; try { socket = acceptor.accept(); //do something with socket } catch (IOException e) { throw new LifecycleException(e); } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /* * @see DefaultLifecycle#destroy0() */ @Override protected void destroy0() throws LifecycleException { if (acceptor != null ) { try { acceptor.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } |
這里的ServerSocket中,init0初始化socket監(jiān)聽,start0開始獲取socket連接, destroy0銷毀socket監(jiān)聽。
在這套生命周期管理機制下,我們將會很容易地對資源進行管理,不會發(fā)生資源未關閉的情況,架構和模塊化更加清晰。
尾聲
到這里為止,本文已經(jīng)實現(xiàn)了一個簡易的生命周期管理機制,并給出所有的實現(xiàn)代碼。之后會將所有源代碼放到github上。請關注本文的update。