淺談Java生命周期管理機(jī)制
先扯再說
最近一直在研究某個(gè)國產(chǎn)開源的MySQL數(shù)據(jù)庫中間件,拉下其最新版的代碼到eclipse后,啟動起來,然后做各種測試和代碼追蹤;用完想要關(guān)閉它時(shí),拉出它的STOP類想要運(yùn)行時(shí),發(fā)現(xiàn)這個(gè)類里赫然只寫以下幾行代碼,于是我感覺瞬間受到了很多傷害。
public static void main(String[] args) { System.out.println(new Date() + ",server shutdown!"); }
這個(gè)中間件啟動和運(yùn)行的時(shí)候,開啟了監(jiān)聽,啟動著許多線程在跑著,并且有許多socket連接。但是并沒有找到一個(gè)優(yōu)雅的方式將其關(guān)閉。于是無奈之下,我只能去點(diǎn)eclipse的心碎小紅點(diǎn),強(qiáng)行停掉VM。
如果是一個(gè)架構(gòu)良好,模塊化清晰的軟件,特別是Server類的軟件,擁有一套生命周期管理機(jī)制是非常重要的。不僅可以管理各個(gè)模塊的生命周期,也可以在啟停整個(gè)軟件的時(shí)候更優(yōu)雅,不會漏掉任何資源。
生命周期機(jī)制簡易實(shí)現(xiàn)
生命周期狀態(tài)
一個(gè)模塊的生命周期狀態(tài)一般有以下幾個(gè):
新生 -> 初始化中 -> 初始化完成 -> 啟動中 -> 啟動完成 -> 正在暫停 -> 已經(jīng)暫停 -> 正在恢復(fù) -> 已經(jīng)恢復(fù) -> 正在銷毀 -> 已經(jīng)銷毀
其中,任何一個(gè)狀態(tài)之間的轉(zhuǎn)化如果失敗,那么就會進(jìn)入另外一種狀態(tài):失敗。
為此,可以用一個(gè)枚舉類來枚舉出這幾個(gè)狀態(tài),如下所示:
public enum LifecycleState { NEW, //新生 INITIALIZING, INITIALIZED, //初始化 STARTING, STARTED, //啟動 SUSPENDING, SUSPENDED, //暫停 RESUMING, RESUMED,//恢復(fù) DESTROYING, DESTROYED,//銷毀 FAILED;//失敗 }
接口
生命周期中的各種行為規(guī)范,也需要一個(gè)接口來定義,如下所示:
public interface ILifecycle { /** * 初始化 * * @throws LifecycleException */ public void init() throws LifecycleException; /** * 啟動 * * @throws LifecycleException */ public void start() throws LifecycleException; /** * 暫停 * * @throws LifecycleException */ public void suspend() throws LifecycleException; /** * 恢復(fù) * * @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)轉(zhuǎn)化時(shí),可能需要觸發(fā)對某類事件感興趣的監(jiān)聽者,因此ILifeCycle也定義了兩個(gè)方法可以添加和移除監(jiān)聽者。分別是:public void addLifecycleListener(ILifecycleListener listener);和 public void removeLifecycleListener(ILifecycleListener listener);
監(jiān)聽者也由一個(gè)接口來定義其行為規(guī)范,如下所示:
public interface ILifecycleListener { /** * 對生命周期事件進(jìn)行處理 * * @param event 生命周期事件 */ public void lifecycleEvent(LifecycleEvent event); }
生命周期事件由LifecycleEvent來表示,如下所示:
public final class LifecycleEvent { private LifecycleState state; public LifecycleEvent(LifecycleState state) { this.state = state; } /** * @return the state */ public LifecycleState getState() { return state; } }
骨架實(shí)現(xiàn)
有了ILifeCycle接口以后,任何實(shí)現(xiàn)了這個(gè)接口的類將會被作為一個(gè)生命周期管理對象,這個(gè)類可以是一個(gè)socket監(jiān)聽服務(wù),也可以代表一個(gè)特定的模塊,等等。那我們是不是只要實(shí)現(xiàn)ILifeCycle就可以了? 可以這么說,但考慮到各個(gè)生命周期管理對象在生命周期的各個(gè)階段會有一些共同的行為,比如說:
設(shè)置自身的生命周期狀態(tài)
檢查狀態(tài)的轉(zhuǎn)換是否符合邏輯
通知監(jiān)聽者生命周期狀態(tài)發(fā)生了變化
因此,提供一個(gè)抽象類AbstractLifeCycle,作為ILifeCycle的骨架實(shí)現(xiàn)是有重要意義的,這樣避免了很多的重復(fù)代碼,使得架構(gòu)更加清晰。這個(gè)抽象類會實(shí)現(xiàn)ILifeCycle中定義的所有接口方法,并添加對應(yīng)的抽象方法,供子類實(shí)現(xiàn)。AbstractLifeCycle可以這么實(shí)現(xiàn):
public abstract class AbstractLifecycle implements ILifecycle { private List<ILifecycleListener> listeners = new CopyOnWriteArrayList<ILifecycleListener>(); /** * state 代表當(dāng)前生命周期狀態(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(); } }
可以看到,抽象類的骨架實(shí)現(xiàn)中做了幾件生命周期管理中通用的事情,檢查狀態(tài)之間的轉(zhuǎn)換是否合法(比如說start之前必須要init),設(shè)置內(nèi)部狀態(tài),以及觸發(fā)相應(yīng)的監(jiān)聽者。
抽象類實(shí)現(xiàn)了ILifeCycle定義的方法后,又留出了相應(yīng)的抽象方法供其子類實(shí)現(xiàn),如上面的代碼所示,其留出來的抽象方法有以下這些:
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)雅的實(shí)現(xiàn)
到目前為止,我們已經(jīng)定義了接口ILifeCycle,以及其骨架實(shí)現(xiàn)AbstractLifeCycle,并且增加了監(jiān)聽者機(jī)制。貌似我們可以開始寫一個(gè)類來繼承AbstractLifecycle,并重寫其定義的抽象方法了,so far so good。
但在開始之前,我們還需要考慮另外幾個(gè)問題,
我們的實(shí)現(xiàn)類是否對所有的抽象方法都感興趣?
是否每個(gè)實(shí)現(xiàn)累都需要實(shí)現(xiàn)init0, start0, suspend0, resume0, destroy0?
是否有時(shí)候,我們的那些有生命的類或者模塊并不支持暫停(suspend),恢復(fù)(resume)?
直接繼承AbstractLifeCycle,就意味著必須實(shí)現(xiàn)其全部的抽象方法。
因此,我們還需要一個(gè)默認(rèn)實(shí)現(xiàn),DefaultLifeCycle,讓它繼承AbstractLifeCycle,并實(shí)現(xiàn)所有抽象方法,但它并不做任何實(shí)際的事情, do nothing。只是讓我們真正的實(shí)現(xiàn)類來繼承這個(gè)默認(rèn)的實(shí)現(xiàn)類,并重寫感興趣的方法。
于是,我們的DefaultLifeCycle就這么誕生了:
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就是其職責(zé)。
因此接下來我們可以寫一個(gè)自己的實(shí)現(xiàn)類,繼承DefaultLifeCycle,并重寫那些感興趣的生命周期方法。
例如,我有一個(gè)類只需要在初始化,啟動,和銷毀時(shí)做一些任務(wù),那么可以這么寫:
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)聽。
在這套生命周期管理機(jī)制下,我們將會很容易地對資源進(jìn)行管理,不會發(fā)生資源未關(guān)閉的情況,架構(gòu)和模塊化更加清晰。
尾聲
到這里為止,本文已經(jīng)實(shí)現(xiàn)了一個(gè)簡易的生命周期管理機(jī)制,并給出所有的實(shí)現(xiàn)代碼。之后會將所有源代碼放到github上。請關(guān)注本文的update。
相關(guān)文章
關(guān)于服務(wù)網(wǎng)關(guān)Spring Cloud Zuul(Finchley版本)
這篇文章主要介紹了關(guān)于服務(wù)網(wǎng)關(guān)Spring Cloud Zuul(Finchley版本),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Spring Boot使用AOP實(shí)現(xiàn)REST接口簡易靈活的安全認(rèn)證的方法
這篇文章主要介紹了Spring Boot使用AOP實(shí)現(xiàn)REST接口簡易靈活的安全認(rèn)證的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-11-11IntelliJ IDEA Project窗口的一些設(shè)置詳解
這篇文章主要介紹了IntelliJ IDEA Project窗口的一些設(shè)置詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08如何優(yōu)雅的拋出Spring Boot注解的異常詳解
這篇文章主要給大家介紹了關(guān)于如何優(yōu)雅的拋出Spring Boot注解的異常的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12SpringBoot實(shí)現(xiàn)跨域的幾種常用方式總結(jié)
跨域是指一個(gè)域下的文檔或腳本試圖去請求另一個(gè)域下的資源,或者涉及到兩個(gè)不同域名的資源之間的交互,由于同源策略(Same Origin Policy)的限制,瀏覽器不允許跨域請求,本文小編給大家分享了SpringBoot實(shí)現(xiàn)跨域的幾種常用方式,需要的朋友可以參考下2023-09-09