买机票便宜网站建设,企业网站建设的意义,成都建设网上办事大厅,网红营销策略【0】REAMDE0#xff09;本文部分文字描述转自#xff1a;“how tomcat works”#xff0c;旨在学习“tomat(16)关闭钩子”的相关知识#xff1b;1#xff09;problemsolution#xff1a;1.1#xff09;problem#xff1a;在很多实际环境中#xff0c;当用户关闭应用程…【0】REAMDE0本文部分文字描述转自“how tomcat works”旨在学习“tomat(16)关闭钩子”的相关知识1problemsolution1.1problem在很多实际环境中当用户关闭应用程序时并不会按照推荐的方法关闭应用程序很有可能不做清理工作 1.2solutionjava 为程序员提供了一种优雅的方法可以在在关闭过程中执行一些代码以确保那些负责善后处理的代码可能能够执行 2在java中虚拟机会对两类事件events进行响应然后执行关闭操作event1当调用System.exit()方法或程序的最后一个非守护进程线程退出时应用程序正常退出 event2用户突然强制虚拟机中断运行例如用户按 CTRLC 快捷键或在未关闭java程序的case下从系统中退出 3虚拟机在执行关闭操作时会经过以下两个阶段stagesstage1虚拟机启动所有已经注册的关闭钩子如果有的话。关闭钩子是先前已经通过 Runtime 类注册的线程所有的关闭钩子会并发执行直到完成任务干货——关闭钩子是线程 stage2虚拟机根据case 调用所有没有被调用过的 终结期finalizer Attention本文重点说明第一个stage因为该阶段允许程序员告诉虚拟机在应用程序中执行一些清理代码。4创建关闭钩子很简单stepsstep1创建Thread类的一个子类 step2实现你自己的run()方法当应用程序正常或突然关闭时会调用此方法 step3在应用程序中实例化关闭钩子类 step4使用当前 Runtime.addShutdownHook() 方法注册关闭钩子 5看个荔枝关于 创建钩子的测试用例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);}
}对以上代码的分析AnalysisA1在实例化ShutdownHookDemo 类后main()方法会调用start()方法start()方法会创建一个关闭钩子并通过当前运行时注册它ShutdownHook shutdownHook new ShutdownHook();Runtime.getRuntime().addShutdownHook(shutdownHook); // 添加一个关闭钩子. A2然后应用程序会等待用户输入 System.in.read();A3当用户按 enter 键后应用程序会退出。虚拟机会执行关闭钩子输入字符串“Shutting down”【1】关闭钩子的荔枝1源代码如下该应用程序在启动时会创建一个临时文件并在关闭时删除该临时文件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();}
}对以上代码的分析Analysis step1应用程序会调用其 initialize()方法 step2initialize()方法会在用户目录中创建一个临时文件名为 “temp.txt” step3当用户关闭应用程序时该程序会删除该临时文件 2problemsolution2.1problem我们希望用户总是能够单击exit 来退出这动作监听器就会调用shutdown()方法可以删除临时文件了但如果用户通过单击右上角的关闭按钮或是通过其他方式强制退出则临时文件就无法删除了 2.2solution使用关闭钩子来删除临时文件关闭钩子是一个内部类这样它就能够访问主类的所有方法干货——关闭钩子是一个内部类这样它就能够访问主类的所有方法 3带有关闭钩子的源代码如下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.}}
}对以上代码的分析Analysisstep1程序会首先创建一个内部类MyShutdownHook的一个实例即钩子类实例并将注册该钩子实例 step2其他的代码与MySwingAppWithoutShutdownHook的源代码类似 Attention唯一不同的是当突然关闭应用程序时该临时文件总是会被删除【2】tomcat中的关闭钩子1introtomcat也是通过关闭钩子来完成退出过程的2org.apache.catalina.startup.Catalina类负责启动管理其他组件的Server对象。一个名为 CatalinaShutdownHook的内部类继承自 java.lang.Thread类提供了run()方法的实现它会调用 Server.stop()方法执行关闭操作Supplement本文习惯性地给出 Catalina.main()方法的调用过程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() // doesnt 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);}}} }}SupplementS1在Catalina实例启动时会实例化关闭钩子并在一个阶段将其添加到 Runtime类中 S2org.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 elementclassName);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 elementclassName);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 elementclassName);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() // doesnt 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);}
}