Java实现生命周期管理机制
先扯再说
最近一直在研究某个国产开源的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。
Java实现生命周期管理机制的更多相关文章
- Android之Android apk动态加载机制的研究(二):资源加载和activity生命周期管理
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 为了 ...
- 4-K8S 部署Java应用及应用程序生命周期管理
1.在kubernetes中部署应用程序流程 准备项目源码-->编译构建-->产出war包,打包到镜像中-->推送到镜像仓库 获取源代码是开发人员提交代码的代码托管地址,有Git.S ...
- Java开发学习(十一)----基于注解开发bean作用范围与生命周期管理
一.注解开发bean作用范围与生命周期管理 前面使用注解已经完成了bean的管理,接下来将通过配置实现的内容都换成对应的注解实现,包含两部分内容:bean作用范围和bean生命周期. 1.1 环境准备 ...
- Uber三代API 生命周期管理平台实现 Uber
Uber三代API 生命周期管理平台实现 - InfoQ https://www.infoq.cn/article/H8Ml6L7vJGQz0efpWvyJ Uber 三代 API 生命周期管理平台实 ...
- ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理
ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...
- Akka(2):Actor生命周期管理 - 监控和监视
在开始讨论Akka中对Actor的生命周期管理前,我们先探讨一下所谓的Actor编程模式.对比起我们习惯的行令式(imperative)编程模式,Actor编程模式更接近现实中的应用场景和功能测试模式 ...
- 004-docker命令-容器生命周期管理、容器操作
1.容器生命周期管理 docker run :创建一个新的容器并运行一个命令 语法:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] OPTIONS说明: - ...
- Tomcat中组件的生命周期管理公共接口Lifecycle
Tomcat的组件都会实现一个Lifecycle接口,以方便组件的生命周期的统一管理 interface Lifecycle 组件生命周期中主要的几个方法 增加监听器,事件委托机制 public vo ...
- TOMCAT源码分析——生命周期管理
前言 从server.xml文件解析出来的各个对象都是容器,比如:Server.Service.Connector等.这些容器都具有新建.初始化完成.启动.停止.失败.销毁等状态.tomcat的实现提 ...
随机推荐
- 使用MFC读写Excel
_Application m_ExlApp; //组件服务器的各个classes _Workbook m_ExlBook; Workbooks m_ExlBooks; _W ...
- C#App.config的使用
为什么使用App.config, 在连接数据的时候将连接字符串写在了类中,如果更换数据库地址,则需要修改这个类,然后重新编译才可以重新连接数据库.在这个时候我们就可以将连接信息放到配置文件App.co ...
- C#之Linq学习笔记【转】
写在前面 其实在09年就已经学习过Linq了,并被她那优美的语法所吸引,只是现在所在的公司还在使用VS2005在.Net2.0的框架下面的开发,所以Linq也很久没有用过了,最近看部门的同事对这个有些 ...
- 安装VS2013的离线MSDN帮助文档
作为vs的初学者,安装帮助文档有利于快速掌握.net的基本语法,对于摸索学习的同学帮助很大. VS2013和VS2012的帮助文档目前为止还是一样 下面是下载地址 http://www.micr ...
- hdu 2200
bc上的题目,很水,有很多方法做吧,题意大概就是给定你票数,然后让你求出票数最多的那个下标...... 之前我用两个for循环分开写,一个是读入,然后是判断,提交就wa,后来网上看了别人的,就是不能分 ...
- Cookies欺骗分析与防护
今天来谈谈cookies欺骗是怎么回事以及如何避免. 用户在登录之后通常会保存用户信息,以便在其他需要权限的页面去验证用户信息是否具有访问权限. 有同学说我在登录的时候已经很注意SQL注入问题了,还有 ...
- MySQL数据库my.cnf配置文件注释详解
我们知道,在MySQL数据库安装完成后,要对my.cnf配置文件进行适当的修改才能充分利用MySQL数据库的功能.但是对于初学者来说,修改my.cnf配置文件似乎是一个比较难的过程.为了解决这个问题, ...
- JDBC连接Oracle数据库时出现的ORA-12505错误及解决办法
转载至http://www.blogjava.net/itspy/archive/2007/12/20/169072.html Oracle 问题描述:今天使用jdbc连接oracle 10.2.0. ...
- jQuery mini ui 2
1.<a class="mini-button" iconCls="icon-add" onclick="addRow()" plai ...
- Linux ulimit 系统资源控制
ulimit 的功能和用法 ulimit 功能简述 假设有这样一种情况,当一台 Linux 主机上同时登陆了 10 个人,在系统资源无限制的情况下,这 10 个用户同时打开了 500 个文档,而假设每 ...