浅谈Java生命周期管理机制
作者:hebedich 发布时间:2022-02-21 19:07:47
先扯再说
最近一直在研究某个国产开源的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项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBa
- ThreadGroup的作用及方法ThreadGroup线程组,java对这个类的描述呢就是“线程组表示一组线程。此外,线程组还可以包括其他
- Android中有两种主要方式使用Service,通过调用Context的startService方法或调用Context的bindServ
- filter类不能注入@Autowired变量问题描述项目中的登录是用了shiro以及filter * 。输入正确的账号密码之后却不能正常登
- 本文实例讲述了Java设计模式之抽象工厂模式。分享给大家供大家参考,具体如下:具体工厂类:生产创建某一类具体产品对象。抽象产品类可以使用接口
- 本文实例讲述了Java泛型与数据库应用。分享给大家供大家参考,具体如下:一 点睛BaseDao定义了基本的数据库增删查改, 之后可以继承该泛
- 目前很多业务使用微服务架构,服务模块划分有这2种方式:服务功能划分业务划分不管哪种方式,一次接口调用都需要多个服务协同完成,其中一个服务出现
- Mybatis Plus流式查询mybatis plus 中自定义如下接口,就可以实现流式查询,mybatis 中同样适用。@Select(
- 在web应用中,常常会遇见点击某个链接会弹出一个新的窗口,或者是相互关联的web应用 ,这样要去操作新窗口中的元素,就需要主机切换到新窗口进
- IO流Java中IO流分为两种,字节流和字符流,顾名思义字节流就是按照字节来读取和写入的,字符刘是按照字符来存取的;常用的文件读取用的就是字
- 当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。导致竞态条件发生的代码区称作临界区。在临界区中使用适当的同步就可以避免
- 项目前端由于采用Extjs4,列表分页需要返回三个参数:totalCount(记录总数)、start(开始位置)、limit(每页条数)。由
- 前言对于数组遍历,基本上每个开发者都写过,遍历本身没什么好说的,但是当我们在遍历的过程中,有一些复杂的业务逻辑时,将会发现代码的层级会逐渐加
- 本文主要给大家介绍java的InputStream 流的使用。(1)FileInputstream: 子类,读取数据的通道使用步骤:1.获取
- springboot集成mybatis关键代码如下:1,添加pom引用 <dependency> <group
- 在上一节中,我带大家学习了详解SpringBoot集成Redis来实现缓存技术方案,尤其是结合Spring Cache的注解的实现方案,接下
- 这篇文章主要介绍了Spring @Transactional注解失效解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- 一、百度百科Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防
- 对接前端后效果展示如图:1、CPU相关信息实体类/** * CPU相关信息 * * @author csp */public class
- 这篇文章主要介绍了JPA save()方法将字段更新为null的解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考