Java實現生命週期管理機制

segmentfault發表於2016-01-19

先扯再說

最近一直在研究某個國產開源的MySQL資料庫中介軟體,拉下其最新版的程式碼到eclipse後,啟動起來,然後做各種測試和程式碼追蹤;用完想要關閉它時,拉出它的STOP類想要執行時,發現這個類裡赫然只寫以下幾行程式碼,於是我感覺瞬間受到了很多傷害。

    public static void main(String[] args) {
        System.out.println(new Date() + ",server shutdown!");
    }

這個中介軟體啟動和執行的時候,開啟了監聽,啟動著許多執行緒在跑著,並且有許多socket連線。但是並沒有找到一個優雅的方式將其關閉。於是無奈之下,我只能去點eclipse的心碎小紅點,強行停掉VM。

如果是一個架構良好,模組化清晰的軟體,特別是Server類的軟體,擁有一套生命週期管理機制是非常重要的。不僅可以管理各個模組的生命週期,也可以在啟停整個軟體的時候更優雅,不會漏掉任何資源。

生命週期機制簡易實現

生命週期狀態

一個模組的生命週期狀態一般有以下幾個:

新生 -> 初始化中 -> 初始化完成 -> 啟動中 -> 啟動完成 -> 正在暫停 -> 已經暫停 -> 正在恢復 -> 已經恢復 -> 正在銷燬 -> 已經銷燬

其中,任何一個狀態之間的轉化如果失敗,那麼就會進入另外一種狀態:失敗。

為此,可以用一個列舉類來列舉出這幾個狀態,如下所示:

public enum LifecycleState {

    NEW, //新生

    INITIALIZING, INITIALIZED, //初始化

    STARTING, STARTED, //啟動

    SUSPENDING, SUSPENDED, //暫停

    RESUMING, RESUMED,//恢復

    DESTROYING, DESTROYED,//銷燬

    FAILED;//失敗

}

介面

生命週期中的各種行為規範,也需要一個介面來定義,如下所示:

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;

    /**
     * 新增生命週期監聽器
     * 
     * @param listener
     */
    public void addLifecycleListener(ILifecycleListener listener);

    /**
     * 刪除生命週期監聽器
     * 
     * @param listener
     */
    public void removeLifecycleListener(ILifecycleListener listener);

}

發生生命週期狀態轉化時,可能需要觸發對某類事件感興趣的監聽者,因此ILifeCycle也定義了兩個方法可以新增和移除監聽者。分別是:public void addLifecycleListener(ILifecycleListener listener); public void removeLifecycleListener(ILifecycleListener listener);

監聽者也由一個介面來定義其行為規範,如下所示:

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;
    }

}

骨架實現

有了ILifeCycle介面以後,任何實現了這個介面的類將會被作為一個生命週期管理物件,這個類可以是一個socket監聽服務,也可以代表一個特定的模組,等等。那我們是不是隻要實現ILifeCycle就可以了? 可以這麼說,但考慮到各個生命週期管理物件在生命週期的各個階段會有一些共同的行為,比如說:

  • 設定自身的生命週期狀態
  • 檢查狀態的轉換是否符合邏輯
  • 通知監聽者生命週期狀態發生了變化

因此,提供一個抽象類AbstractLifeCycle,作為ILifeCycle骨架實現是有重要意義的,這樣避免了很多的重複程式碼,使得架構更加清晰。這個抽象類會實現ILifeCycle中定義的所有介面方法,並新增對應的抽象方法,供子類實現。AbstractLifeCycle可以這麼實現:

public abstract class AbstractLifecycle implements ILifecycle {

    private List<ILifecycleListener> listeners = new CopyOnWriteArrayList<ILifecycleListener>();

    /**
     * state 代表當前生命週期狀態
     */
    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();
    }
}

可以看到,抽象類的骨架實現中做了幾件生命週期管理中通用的事情,檢查狀態之間的轉換是否合法(比如說start之前必須要init),設定內部狀態,以及觸發相應的監聽者。

抽象類實現了ILifeCycle定義的方法後,又留出了相應的抽象方法供其子類實現,如上面的程式碼所示,其留出來的抽象方法有以下這些:

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;

優雅的實現

到目前為止,我們已經定義了介面ILifeCycle,以及其骨架實現AbstractLifeCycle,並且增加了監聽者機制。貌似我們可以開始寫一個類來繼承AbstractLifecycle,並重寫其定義的抽象方法了,so far so good。

但在開始之前,我們還需要考慮另外幾個問題,

  • 我們的實現類是否對所有的抽象方法都感興趣?
  • 是否每個實現累都需要實現init0, start0, suspend0, resume0, destroy0?
  • 是否有時候,我們的那些有生命的類或者模組並不支援暫停(suspend),恢復(resume)?

直接繼承AbstractLifeCycle,就意味著必須實現其全部的抽象方法。
因此,我們還需要一個預設實現,DefaultLifeCycle,讓它繼承AbstractLifeCycle,並實現所有抽象方法,但它並不做任何實際的事情, do nothing。只是讓我們真正的實現類來繼承這個預設的實現類,並重寫感興趣的方法。

於是,我們的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就是其職責。
因此接下來我們可以寫一個自己的實現類,繼承DefaultLifeCycle,並重寫那些感興趣的生命週期方法。

例如,我有一個類只需要在初始化,啟動,和銷燬時做一些任務,那麼可以這麼寫:

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監聽,start0開始獲取socket連線, destroy0銷燬socket監聽。
在這套生命週期管理機制下,我們將會很容易地對資源進行管理,不會發生資源未關閉的情況,架構和模組化更加清晰。

尾聲

到這裡為止,本文已經實現了一個簡易的生命週期管理機制,並給出所有的實現程式碼。之後會將所有原始碼放到github上。請關注本文的update。

相關文章