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

