Shutdown钩子
在很多环境下,当用户停止应用以后,程序需要做一些清理。但问题是用户往往忘记按照要求退出,比如在Tomcat部署的时候,你通过实例化Server变量,调用其的start方法来启动servlet和其他的组件,在正常情况下你需要传入一个stutdown命令来停止Server及其它的组件,但是有时你可能直接关闭控制台。
Java本身提供了很好的方案来解决在停止进程中执行相关操作,这里将会为Tomcat添加一个Shutdown钩子程序。
在两种情况下jvm都会退出:
1、 在代码里面显示的调用System.exit()或最后的最后一个后台线程退出以后;
2、 用户强制jvm退出,如通过CTRL+C或者关闭控制台等。
在退出时,虚拟机会做两件事:
1、 如果有启动所有的Shutdown钩子,并发做相应的处理;
2、 调用所有还没有调用的finalizers。
Shutdown钩子程序刚好可以做一些清理工作,stutdown钩子都是Thread类子类的实例,创建一个shutdown钩子:
1、 写一个类继承Thread;
2、 重写其中的run方法,run方法里面的操作就是将来jvm退出的时候你需要清理的操作;
3、 在应用中实例化shutdown钩子类;
4、 通过当前线程的addShutdownHook方法注册钩子程序。
Tomcat中装备了它自己的Shutdown钩子,在负责启动Server类的org.apache.catalina.startup.Catalina中有钩子程序的实现:
protected class CatalinaShutdownHook extends Thread {
public void run() {
if (server != null) {
try {
((Lifecycle) server).stop();
} catch (LifecycleException e) {
System.out.println("Catalina.stop: " + e);
e.printStackTrace(System.out);
if (e.getThrowable() != null) {
System.out.println("----- Root Cause -----");
e.getThrowable().printStackTrace(System.out);
}
}
}
}
}
在启动Server方法时注册了钩子程序:
Thread shutdownHook = new CatalinaShutdownHook();
// Start the new server
if (server instanceof Lifecycle) {
try {
server.initialize();
((Lifecycle) server).start();
try {
// Register shutdown hook
Runtime.getRuntime().addShutdownHook(shutdownHook);
} catch (Throwable t) {
// This will fail on JDK 1.2. Ignoring, as Tomcat can run
// fine without the shutdown hook.
}
// Wait for the server to be told to shut down
server.await();
} catch (LifecycleException e) {
System.out.println("Catalina.start: " + e);
e.printStackTrace(System.out);
if (e.getThrowable() != null) {
System.out.println("----- Root Cause -----");
e.getThrowable().printStackTrace(System.out);
}
}
}