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