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