浅谈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。

(0)

相关推荐

  • java多线程编程之线程的生命周期

    复制代码 代码如下: // 开始线程public void start( );public void run( ); // 挂起和唤醒线程public void resume( ); // 不建议使用public void suspend( );// 不建议使用public static void sleep(long millis);public static void sleep(long millis, int nanos); // 终止线程public void stop( );   /

  • 初步学习Java中线程的实现与生命周期

    线程的实现 在Java中通过run方法为线程指明要完成的任务,有两种技术来为线程提供run方法: 1.继承Thread类并重写它的run方法.之后创建这个子类的对象并调用start()方法. 2.通过定义实现Runnable接口的类进而实现run方法.这个类的对象在创建Thread的时候作为参数被传入,然后调用start()方法. Thread类是专门用来创建线程和对线程进行操作的类.当某个类继承了Thread类之后,该类就叫做一个线程类. 两种方法均需执行线程的start()方法为线程分配必须

  • 深入讲解Java编程中类的生命周期

    引言         最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你"怎样做",但至于"为什么这样做"却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正.         首先来了

  • Java线程的生命周期和状态控制_动力节点Java学院整理

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(runnable). 注意:不能对已经启动的线程再次调用start()方法,否则会出现Javalang.IllegalThreadStateException异常. 2.就绪状态 处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它称

  • java 线程的生命周期详解

    一个线程的生命周期: 新建状态: 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态.它保持这个状态直到程序 start() 这个线程. 就绪状态: 当线程对象调用了start()方法之后,该线程就进入就绪状态.就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度. 运行状态: 如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态.处于运行状态的线程最为复杂,它可以变为阻塞状态.就绪状态和死亡状态. 阻塞状态: 如

  • Java 线程的生命周期详细介绍及实例代码

    当线程被创建并启动之后,它既不是一启动就进入执行状态,也不是一直处于执行状态,在其生命周期中,要经过"新建(New)"."就绪(Runnable)"."运行(Running')"."阻塞(Blocked)"和"死亡(Dead)"五种状态.线程在创建之后,不可能一直霸占着CPU独立运行,需要在多个线程之间切换,所以大部分时间处于运行.阻塞之间切换.  一.线程的状态 线程的存在有几种不同的状态,如下: New

  • 详解Java的Spring框架中bean的定义以及生命周期

    bean的定义 形成应用程序的骨干是由Spring IoC容器所管理的对象称为bean.bean被实例化,组装,并通过Spring IoC容器所管理的对象.这些bean由容器提供,例如,在XML的<bean/>定义,已经看到了前几章的形式配置元数据创建. bean定义包含所需要的容器要知道以下称为配置元数据的信息: 如何创建一个bean Bean 生命周期的详细信息 Bean 依赖关系 上述所有配置元数据转换成一组的下列属性构成每个bean的定义. Spring配置元数据 Spring IoC

  • servlet生命周期_动力节点Java学院整理

    本文为大家分享了servlet生命周期的相关资料,供大家参考,具体内容如下 1.Servlet 生命周期:Servlet 加载--->实例化--->服务--->销毁. 2.init():在Servlet的生命周期中,仅执行一次init()方法.它是在服务器装入Servlet时执行的,负责初始化Servlet对象.可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet.无论有多少客户机访问Servlet,都不会重复执行init(). 3.service():它是S

  • 图解Java线程的生命周期

    在Java中,线程有5中不同状态,分别是:新建(New).就绪(Runable).运行(Running).阻塞(Blocked)和死亡(Dead).它们之间的转换图如下: 上图有一个例外,调用yield()方法可以让当前处于运行状态的线程转入就绪状态.如果要测试某线程是否已经死亡,可以使用isAlive()方法,该方法在线程处于就绪.运行.阻塞时放回true,新建和死亡时返回false.不要试图对一个已经死亡的线程调用start()方法而重新启动,死亡就是死亡和人一样,不可能再生.还有也不要对一

  • Java 详解垃圾回收与对象生命周期

    Java 垃圾回收与对象生命周期详解 Java中的垃圾回收与对象生命周期 1. 垃圾回收 垃圾回收是Java程序设计中内存管理的核心概念,JVM的内存管理机制被称为垃圾回收机制. 一个对象创建后被放置在JVM的堆内存中,当永远不再引用这个对象时,它将被JVM在堆内存中回收.被创建的对象不能再生,同时也没有办法通过程序语句释放它们.即当对象在JVM运行空间中无法通过根集合到达(找到)时,这个对象被称为垃圾对象.根集合是由类中的静态引用域与本地引用域组成的.JVM通过根集合索引对象. 在做Java应

随机推荐