tomat(16)关闭钩子
1.1)problem:在很多实际环境中,当用户关闭应用程序时,并不会按照推荐的方法关闭应用程序,很有可能不做清理工作;1.2)solution:java 为程序员提供了一种优雅的方法可以在在关闭过程中执行一些代码,以确保那些负责善后处理的代码可能能够执行;
event1)当调用System.exit()方法或程序的最后一个非守护进程线程退出时,应用程序正常退出;event2)用户突然强制虚拟机中断运行,例如用户按 CTRL+C 快捷键或在未关闭java程序的case下,从系统中退出;
stage1)虚拟机启动所有已经注册的关闭钩子,如果有的话。关闭钩子是先前已经通过 Runtime 类注册的线程,所有的关闭钩子会并发执行,直到完成任务;(干货——关闭钩子是线程)stage2)虚拟机根据case 调用所有没有被调用过的 终结期(finalizer);
step1)创建Thread类的一个子类 ;step2)实现你自己的run()方法,当应用程序(正常或突然)关闭时,会调用此方法;step3)在应用程序中,实例化关闭钩子类;step4)使用当前 Runtime.addShutdownHook() 方法注册关闭钩子;
package com.tomcat.chapter16.shutdownhook;public class ShutdownHookDemo {public void start() {System.out.println("Demo");ShutdownHook shutdownHook = new ShutdownHook();Runtime.getRuntime().addShutdownHook(shutdownHook); // 添加一个关闭钩子.}public static void main(String[] args) {ShutdownHookDemo demo = new ShutdownHookDemo();demo.start();try {System.in.read();} catch (Exception e) {}System.out.println("Normal exit");}
}class ShutdownHook extends Thread {public void run() {System.out.println("Shutting down");}
}
ShutdownHook shutdownHook = new ShutdownHook();Runtime.getRuntime().addShutdownHook(shutdownHook); // 添加一个关闭钩子.
A2)然后,应用程序会等待用户输入: System.in.read();
public class MySwingAppWithoutShutdownHook extends JFrame { //不带有关闭钩子的swingJButton exitButton = new JButton();JTextArea jTextArea1 = new JTextArea();String dir = System.getProperty("user.dir");String filename = "temp.txt";public MySwingApp() {exitButton.setText("Exit");exitButton.setBounds(new Rectangle(304, 248, 76, 37));exitButton.addActionListener(new java.awt.event.ActionListener() {public void actionPerformed(ActionEvent e) {exitButton_actionPerformed(e);}});this.getContentPane().setLayout(null);jTextArea1.setText("Click the Exit button to quit");jTextArea1.setBounds(new Rectangle(9, 7, 371, 235));this.getContentPane().add(exitButton, null);this.getContentPane().add(jTextArea1, null);this.setDefaultCloseOperation(EXIT_ON_CLOSE);this.setBounds(0, 0, 400, 330);this.setVisible(true);initialize();}private void initialize() {// create a temp fileFile file = new File(dir, filename);try {System.out.println("Creating temporary file");file.createNewFile();} catch (IOException e) {System.out.println("Failed creating temporary file.");}}private void shutdown() {// delete the temp fileFile file = new File(dir, filename);if (file.exists()) {System.out.println("Deleting temporary file.");file.delete();}}void exitButton_actionPerformed(ActionEvent e) {shutdown();System.exit(0);}public static void main(String[] args) {MySwingApp mySwingApp = new MySwingApp();}
}
step1)应用程序会调用其 initialize()方法;step2)initialize()方法会在用户目录中创建一个临时文件,名为 “temp.txt”;step3)当用户关闭应用程序时,该程序会删除该临时文件;
2.1)problem:我们希望用户总是能够单击exit 来退出,这动作监听器就会调用shutdown()方法,可以删除临时文件了;但如果用户通过单击右上角的关闭按钮或是通过其他方式强制退出,则临时文件就无法删除了;2.2)solution:使用关闭钩子来删除临时文件;关闭钩子是一个内部类,这样它就能够访问主类的所有方法;(干货——关闭钩子是一个内部类,这样它就能够访问主类的所有方法)
public class MySwingAppWithShutdownHook extends JFrame { // 带有关闭钩子的swing.JButton exitButton = new JButton();JTextArea jTextArea1 = new JTextArea();String dir = System.getProperty("user.dir");String filename = "temp.txt";public MySwingAppWithShutdownHook() {exitButton.setText("Exit");exitButton.setBounds(new Rectangle(304, 248, 76, 37));exitButton.addActionListener(new java.awt.event.ActionListener() {public void actionPerformed(ActionEvent e) {exitButton_actionPerformed(e);}});this.getContentPane().setLayout(null);jTextArea1.setText("Click the Exit button to quit");jTextArea1.setBounds(new Rectangle(9, 7, 371, 235));this.getContentPane().add(exitButton, null);this.getContentPane().add(jTextArea1, null);this.setDefaultCloseOperation(EXIT_ON_CLOSE);this.setBounds(0,0, 400, 330);this.setVisible(true);initialize();}private void initialize() {// add shutdown hookMyShutdownHook shutdownHook = new MyShutdownHook();Runtime.getRuntime().addShutdownHook(shutdownHook);// create a temp fileFile file = new File(dir, filename);try {System.out.println("Creating temporary file");file.createNewFile();}catch (IOException e) {System.out.println("Failed creating temporary file.");}}private void shutdown() { // highlight line.// delete the temp fileFile file = new File(dir, filename);if (file.exists()) {System.out.println("Deleting temporary file.");file.delete();}}void exitButton_actionPerformed(ActionEvent e) {shutdown();System.exit(0);}public static void main(String[] args) {MySwingAppWithShutdownHook mySwingApp = new MySwingAppWithShutdownHook();}private class MyShutdownHook extends Thread { // highlight line.public void run() {shutdown(); // highlight line.}}
}
step1)程序会首先创建一个内部类MyShutdownHook的一个实例,即钩子类实例,并将注册该钩子实例;step2)其他的代码与MySwingAppWithoutShutdownHook的源代码类似;
protected void start() { //org.apache.catalina.startup.Catalina.start().//..... // Replace System.out and System.err with a custom PrintStreamSystemLogHandler log = new SystemLogHandler(System.out);System.setOut(log);System.setErr(log);Thread shutdownHook = new CatalinaShutdownHook(); // 创建关闭钩子// Start the new serverif (server instanceof Lifecycle) {try {server.initialize();((Lifecycle) server).start();try {// Register shutdown hookRuntime.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 downserver.await();} //......}// Shut down the serverif (server instanceof Lifecycle) {try {try {// Remove the ShutdownHook first so that server.stop() // doesn't get invoked twiceRuntime.getRuntime().removeShutdownHook(shutdownHook);} catch (Throwable t) {// This will fail on JDK 1.2. Ignoring, as Tomcat can run// fine without the shutdown hook.}((Lifecycle) server).stop();} //......}}
protected class CatalinaShutdownHook extends Thread { //org.apache.catalina.startup.Catalina.CatalinaShutdownHook
// an inner class defined in Catalinapublic void run() {if (server != null) {try {((Lifecycle) server).stop(); // highlight line.} 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);}}} }}
S1)在Catalina实例启动时,会实例化关闭钩子,并在一个阶段将其添加到 Runtime类中;S2)org.apache.catalina.startup.Catalina 类的源代码如下所示:(其中Catalina.createStartDigester() 创建了很多规则,规则集参见 tomcat(15)Digester库)public class Catalina { protected String configFile = "conf/server.xml"; protected boolean debug = false; protected ClassLoader parentClassLoader =ClassLoader.getSystemClassLoader(); protected Server server = null; protected boolean starting = false; protected boolean stopping = false; protected boolean useNaming = true; public static void main(String args[]) {(new Catalina()).process(args);}public void process(String args[]) {setCatalinaHome();setCatalinaBase();try {if (arguments(args))execute();} catch (Exception e) {e.printStackTrace(System.out);}}public void setParentClassLoader(ClassLoader parentClassLoader) {this.parentClassLoader = parentClassLoader;}public void setServer(Server server) {this.server = server;} protected boolean arguments(String args[]) {boolean isConfig = false;if (args.length < 1) {usage();return (false);}for (int i = 0; i < args.length; i++) {if (isConfig) {configFile = args[i];isConfig = false;} else if (args[i].equals("-config")) {isConfig = true;} else if (args[i].equals("-debug")) {debug = true;} else if (args[i].equals("-nonaming")) {useNaming = false;} else if (args[i].equals("-help")) {usage();return (false);} else if (args[i].equals("start")) {starting = true;} else if (args[i].equals("stop")) {stopping = true;} else {usage();return (false);}}return (true);}protected File configFile() {File file = new File(configFile);if (!file.isAbsolute())file = new File(System.getProperty("catalina.base"), configFile);return (file);}protected Digester createStartDigester() {// Initialize the digesterDigester digester = new Digester();digester.setClassLoader(StandardServer.class.getClassLoader());if (debug)digester.setDebug(999);digester.setValidating(false);// Configure the actions we will be usingdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addSetProperties("Server/GlobalNamingResources");digester.addSetNext("Server/GlobalNamingResources","setGlobalNamingResources","org.apache.catalina.deploy.NamingResources");digester.addObjectCreate("Server/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");digester.addObjectCreate("Server/Service/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Listener");digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service/Connector","org.apache.catalina.connector.http.HttpConnector","className");digester.addSetProperties("Server/Service/Connector");digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.Connector");digester.addObjectCreate("Server/Service/Connector/Factory","org.apache.catalina.net.DefaultServerSocketFactory","className");digester.addSetProperties("Server/Service/Connector/Factory");digester.addSetNext("Server/Service/Connector/Factory","setFactory","org.apache.catalina.net.ServerSocketFactory");digester.addObjectCreate("Server/Service/Connector/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/Listener");digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");// Add RuleSets for nested elementsdigester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));digester.addRuleSet(new EngineRuleSet("Server/Service/"));digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));digester.addRule("Server/Service/Engine",new SetParentClassLoaderRule(digester,parentClassLoader));return (digester);} protected Digester createStopDigester() {// Initialize the digesterDigester digester = new Digester();if (debug)digester.setDebug(999);// Configure the rules we need for shutting downdigester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");return (digester);} protected void execute() throws Exception {if (starting)start();else if (stopping)stop();}protected void setCatalinaBase() {if (System.getProperty("catalina.base") != null)return;System.setProperty("catalina.base",System.getProperty("catalina.home"));} protected void setCatalinaHome() {if (System.getProperty("catalina.home") != null)return;System.setProperty("catalina.home",System.getProperty("user.dir"));} protected void start() {// Setting additional variablesif (!useNaming) {System.setProperty("catalina.useNaming", "false");} else {System.setProperty("catalina.useNaming", "true");String value = "org.apache.naming";String oldValue =System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);if (oldValue != null) {value = value + ":" + oldValue;}System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);value = System.getProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY);if (value == null) {System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,"org.apache.naming.java.javaURLContextFactory");}}// Create and execute our DigesterDigester digester = createStartDigester();File file = configFile();try {InputSource is =new InputSource("file://" + file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);is.setByteStream(fis);digester.push(this);digester.parse(is);fis.close();} catch (Exception e) {System.out.println("Catalina.start using "+ configFile() + ": " + e);e.printStackTrace(System.out);System.exit(1);}// If a SecurityManager is being used, set properties for// checkPackageAccess() and checkPackageDefinitionif( System.getSecurityManager() != null ) {String access = Security.getProperty("package.access");if( access != null && access.length() > 0 )access += ",";elseaccess = "sun.,";Security.setProperty("package.access",access + "org.apache.catalina.,org.apache.jasper.");String definition = Security.getProperty("package.definition");if( definition != null && definition.length() > 0 )definition += ",";elsedefinition = "sun.,";Security.setProperty("package.definition",// FIX ME package "javax." was removed to prevent HotSpot// fatal internal errorsdefinition + "java.,org.apache.catalina.,org.apache.jasper.,org.apache.coyote.");}// Replace System.out and System.err with a custom PrintStreamSystemLogHandler log = new SystemLogHandler(System.out);System.setOut(log);System.setErr(log);Thread shutdownHook = new CatalinaShutdownHook();// Start the new serverif (server instanceof Lifecycle) {try {server.initialize();((Lifecycle) server).start();try {// Register shutdown hookRuntime.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 downserver.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);}}}// Shut down the serverif (server instanceof Lifecycle) {try {try {// Remove the ShutdownHook first so that server.stop() // doesn't get invoked twiceRuntime.getRuntime().removeShutdownHook(shutdownHook);} catch (Throwable t) {// This will fail on JDK 1.2. Ignoring, as Tomcat can run// fine without the shutdown hook.}((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);}}}}protected void stop() {// Create and execute our DigesterDigester digester = createStopDigester();File file = configFile();try {InputSource is =new InputSource("file://" + file.getAbsolutePath());FileInputStream fis = new FileInputStream(file);is.setByteStream(fis);digester.push(this);digester.parse(is);fis.close();} catch (Exception e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);System.exit(1);}// Stop the existing servertry {Socket socket = new Socket("127.0.0.1", server.getPort());OutputStream stream = socket.getOutputStream();String shutdown = server.getShutdown();for (int i = 0; i < shutdown.length(); i++)stream.write(shutdown.charAt(i));stream.flush();stream.close();socket.close();} catch (IOException e) {System.out.println("Catalina.stop: " + e);e.printStackTrace(System.out);System.exit(1);}} protected void usage() {System.out.println("usage: java org.apache.catalina.startup.Catalina"+ " [ -config {pathname} ] [ -debug ]"+ " [ -nonaming ] { start | stop }");} 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);}}} }} } final class SetParentClassLoaderRule extends Rule {public SetParentClassLoaderRule(Digester digester,ClassLoader parentClassLoader) {super(digester);this.parentClassLoader = parentClassLoader;}ClassLoader parentClassLoader = null;public void begin(Attributes attributes) throws Exception {if (digester.getDebug() >= 1)digester.log("Setting parent class loader");Container top = (Container) digester.peek();top.setParentClassLoader(parentClassLoader);} }
tomat(16)关闭钩子相关推荐
- JAVA虚拟机关闭钩子(Shutdown Hook)
Java程序经常也会遇到进程挂掉的情况,一些状态没有正确的保存下来,这时候就需要在JVM关掉的时候执行一些清理现场的代码.JAVA中的ShutdownHook提供了比较好的方案. JDK提供了Java ...
- layui.open 关闭之后触发_JAVA虚拟机关闭钩子(Shutdown Hook)
前言 当你认真的去看一个组件的源码的时候,你会经常看见这种关闭钩子的函数,如果你不了解的话,谷歌一下,你就会发现如下文章就是搜索引擎出来的第一篇,不愧是出自我们优秀的厮哒哒之笔. 正文 Java 程序 ...
- Java中的JVM关闭钩子
java面试题网站:www.javaoffers.com Java中的JVM关闭钩子 (翻译篇)关机钩子 也叫 关闭钩子 关机钩子是一种特殊的构造,允许开发人员插入一段代码,以便在JVM关闭时执行.当 ...
- 关闭钩子(shutdown hool)
Java提供了一种优雅的方式供程序员来使用,这样可以保证清理代码的执行.本章将会说明如何使用一个关闭钩子(shutdown hool)来保证清理代码一定会被执行. 在Java中,虚拟机遇到两种事件的时 ...
- 深入JVM关闭与关闭钩子
1. 简述JVM关闭 通常而言,对于JVM的关闭我们很少去关注,但是了解JVM的关闭能帮我们在JVM关闭时做一些合理的事情.首先JVM的关闭方式可以分为三种: 正常关闭:当最后一个非守护线程结束或者调 ...
- nodemanager不能正常关闭_Java虚拟机关闭钩子(Shutdown hook)
作者:俩右 出处:https://segmentfault.com/a/1190000038298447 源码点击 study:https://github.com/xiaoshuanglee/stu ...
- 关闭钩子(ShutdownHook)
http://www.blogjava.net/zJun/archive/2006/03/12/34946.html 关闭钩子"(ShutdownHook)是这样一个概念:向虚拟机注册一个线 ...
- tomcat 正常关闭_Tomcat的带有守护程序和关闭钩子的正常关闭
tomcat 正常关闭 我的最后两个博客讨论了长时间轮询和Spring的DeferredResult技术,并且为了展示这些概念,我将我的Producer Consumer项目中的代码添加到了Web应用 ...
- java 自定义 钩子_Java添加关闭钩子里面的方法
在我的代码中,我使用CompletionService和ExecutorService来启动一堆Thread来执行某些任务(这可能需要很长时间) . 所以我有一个创建ExecutorService和C ...
最新文章
- 原生js写三级联动 java_原生js三级联动的简单实现代码
- 6-11数据库mysql初始
- python中class变量_对python 中class与变量的使用方法详解
- 全国计算机运用计算机绘图考试,计算机绘图期末考试题库
- Pytorch基础(九)——损失函数
- mvc的Controller返回值类型ActionResult详解
- EF(Entity FrameWork)实体框架
- 分布式唯一ID的几种生成方案
- mysql备份时过滤掉某些库 以及 去掉Warning: Using a password on the command line interface can be insecure.提示信息...
- 求计算机技术在创新上的应用,计算机技术在教学上的应用
- chrome http请求,测试webapp接口之DHC - REST/HTTP API Client
- 雷军立 Flag:小米 5 年 100 亿 All in AIoT
- 【软件测试】单元测试不属于动态测试
- C#类、方法的访问修饰符
- basename 从绝对路径中取得文件名
- 权限管理模块数据库设计
- 哪上班 | 好工作近在咫尺
- 基于EasyNVR实现RTSP/Onvif监控摄像头Web无插件化直播监控
- 快速高效入门3D建模学习教程,让你最快从小白到建模大师!
- CITA Release v0.18
热门文章
- 2020牛客多校第1场I-1 or 2一般图最大匹配带花树
- cf1555 E. Boring Segments
- [JLOI2015]战争调度
- 二分:[BJWC2008]秦腾与教学评估
- P3293-[SCOI2016]美味【主席树】
- P4300-[AHOI2006]上学路线【网络流,最短路】
- 【DP】剪草(jzoj 1510)
- 【dfs】简单游戏(jzoj 2121)
- P2053 SCOI2007 修车,费用流好题
- 数学推导题,NTT,快速数论变换,Wannafly-乒乓球