tomat(16)关闭钩子

【0】REAMDE
0)本文部分文字描述转自:“how tomcat works”,旨在学习“tomat(16)关闭钩子”的相关知识;
1)problem+solution:
1.1)problem:在很多实际环境中,当用户关闭应用程序时,并不会按照推荐的方法关闭应用程序,很有可能不做清理工作;
1.2)solution:java 为程序员提供了一种优雅的方法可以在在关闭过程中执行一些代码,以确保那些负责善后处理的代码可能能够执行;
2)在java中,虚拟机会对两类事件(events)进行响应,然后执行关闭操作:
event1)当调用System.exit()方法或程序的最后一个非守护进程线程退出时,应用程序正常退出;
event2)用户突然强制虚拟机中断运行,例如用户按 CTRL+C 快捷键或在未关闭java程序的case下,从系统中退出;
3)虚拟机在执行关闭操作时,会经过以下两个阶段(stages):
stage1)虚拟机启动所有已经注册的关闭钩子,如果有的话。关闭钩子是先前已经通过 Runtime 类注册的线程,所有的关闭钩子会并发执行,直到完成任务;(干货——关闭钩子是线程)
stage2)虚拟机根据case 调用所有没有被调用过的 终结期(finalizer);
Attention)本文重点说明第一个stage,因为该阶段允许程序员告诉虚拟机在应用程序中执行一些清理代码。
4)创建关闭钩子很简单(steps):
step1)创建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");}
}
对以上代码的分析(Analysis):
A1)在实例化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()方法;
step2)initialize()方法会在用户目录中创建一个临时文件,名为 “temp.txt”;
step3)当用户关闭应用程序时,该程序会删除该临时文件;
2)problem+solution
2.1)problem:我们希望用户总是能够单击exit 来退出,这动作监听器就会调用shutdown()方法,可以删除临时文件了;但如果用户通过单击右上角的关闭按钮或是通过其他方式强制退出,则临时文件就无法删除了;
2.2)solution:使用关闭钩子来删除临时文件;关闭钩子是一个内部类,这样它就能够访问主类的所有方法;(干货——关闭钩子是一个内部类,这样它就能够访问主类的所有方法)
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.}}
}
对以上代码的分析(Analysis):
step1)程序会首先创建一个内部类MyShutdownHook的一个实例,即钩子类实例,并将注册该钩子实例;
step2)其他的代码与MySwingAppWithoutShutdownHook的源代码类似;
Attention)唯一不同的是,当突然关闭应用程序时,该临时文件总是会被删除;

【2】tomcat中的关闭钩子
1)intro:tomcat也是通过关闭钩子来完成退出过程的;
2)org.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() // 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);}}}              }}
Supplement)
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);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331161.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

apache.camel_Apache Camel 3.1 – XML路由的快速加载

apache.camelCamel 3.1中添加的一项功能是能够更快地加载XML路由。 这是我们为使Camel变得更小&#xff0c;更快而进行的总体工作的一部分。 您可能会说ewww XML。 但坦率地说&#xff0c;有很多Camel用户使用XML定义路由来构建应用程序。 在Camel 2.x中&#xff0c;您将不得不…

程序中 设置jvm 参数_高效应用程序的7个JVM参数

程序中 设置jvm 参数在撰写本文时&#xff08;2020年3月&#xff09;&#xff0c;围绕垃圾收集和内存&#xff0c;您可以将600多个参数传递给JVM。 如果您包括其他方面&#xff0c;则JVM参数总数将很容易超过1000个。 &#x1f60a;。 任何人都无法消化和理解太多的论据。 在本…

tomcat(17)启动tomcat

【0】README 1&#xff09;本文部分文字描述转自“how tomcat works”&#xff0c;旨在学习“tomcat(17)启动tomcat”的相关知识&#xff1b;2&#xff09;本文重点关注启动Tomcat时会用到的两个类&#xff0c;分别是Catalina类和 Bootstrap类&#xff1b;&#xff08;干货——…

八爪鱼 是java做的吗_章鱼扫描仪:Java构建工具和恶意软件

八爪鱼 是java做的吗Alvaro Munoz最近在GitHub Security Lab网站上发布了“ Octopus扫描程序恶意软件&#xff1a;攻击开源供应链 ”。 我发现这篇文章很有趣&#xff0c;原因有很多&#xff0c;其中包括对Octopus Scanner恶意软件的工作原理和发现方式的详细介绍&#xff0c; …

spring(1)Spring之旅

【0】README0.1&#xff09;本文部分文字描述转自&#xff1a;“Spring In Action&#xff08;中/英文版&#xff09;”&#xff0c;旨在reviewSpring(1)Spring之旅 的相关知识&#xff1b;【1】简化java 开发1&#xff09;为了降低java开发的复杂性&#xff0c;Spring采取了以…

apache.camel_Apache Camel K 1.0在这里–您为什么要关心

apache.camel昨天我们发布了Apache Camel K 1.0&#xff0c;并在社交媒体和Camel网站上宣布了该版本。 那么&#xff0c;骆驼K是什么&#xff0c;为什么你要在乎呢&#xff1f; 这是一个很好的问题&#xff0c;我想通过提及伟大的思想来帮助回答这个问题。 Hugo Guerrero发表…

DRF之初识

目录 一、序列化和反序列化 【1】序列化 【2】反序列化 【3】小结 二、DRF的安装和快速使用 (1) 安装DRF&#xff1a; (2) 配置DRF&#xff1a; (3) 创建序列化器(Serializer)&#xff1a; (4) 创建视图(View)&#xff1a; (5) 配置URL路由&#xff1a; 【补充】下载…

spring(2)装配Bean

【0】README0&#xff09;本文部分文字描述转自&#xff1a;“Spring In Action&#xff08;中/英文版&#xff09;”&#xff0c;旨在review spring(2)装配Bean 的相关知识&#xff1b;1&#xff09;在spring中&#xff0c;对象无需自己查找或创建与其所关联的其他对象。相反…

restful和rest_HATEOAS的RESTful服务:JVM上的REST API和超媒体

restful和rest1.简介 到目前为止&#xff0c;我们已经花了很多时间谈论了相当数量的关于角色的的超媒体和HATEOAS在REST风格的 Web服务和API&#xff0c;扫视不同规格和可用性方面。 听起来好像支持超媒体和HATEOAS并不难&#xff0c;只需选择您的收藏夹就可以了&#xff01; …

Spring中配置数据源的4种形式

【0】README 0.1&#xff09;以下内容转自&#xff1a;http://blog.csdn.net/orclight/article/details/8616103 不管采用何种持久化技术&#xff0c;都需要定义数据源。Spring中提供了4种不同形式的数据源配置方式&#xff1a; spring自带的数据源(DriverManagerDataSource)&…

MavenSelenium测试自动化教程

在进行自动化测试项目时&#xff0c;您需要与之关联的所有Selenium依赖项。 通常&#xff0c;这些依赖项是在项目生命周期中手动下载和升级的&#xff0c;但是随着项目规模的扩大&#xff0c;管理依赖项可能会非常困难。 这就是为什么需要构建自动化工具&#xff08;例如Maven&…

命令行执行Junit测试

【0】README 0.1&#xff09;本文旨在给出如何在命令行中执行 Junit测试的steps&#xff1a; 【1】在命令行中执行Junit测试 1&#xff09;problemsolution&#xff1a; 1.1&#xff09;problem&#xff1a; 1.2&#xff09;solution&#xff1a;导出 JUnitCore 类并且使用 …

托管 非托管_如何在托管Kubernetes上还原Neo4J备份

托管 非托管在下面的视频中&#xff0c;我将解释如何将Neo4J实例的备份还原到在托管Kubernetes环境中运行的新实例。 备份内容将从先前写入备份的持久卷中获取。 在上一篇文章中&#xff0c;您可以首先了解如何进行备份。 自己尝试 同样&#xff0c;您将在以下GitHub存储库中…

spring(3)高级装配

【0】README0&#xff09;本文部分文字描述转自&#xff1a;“Spring In Action&#xff08;中/英文版&#xff09;”&#xff0c;旨在review spring(3)高级装配 的相关知识&#xff1b;【1】环境与profile&#xff08;考虑数据库配置&#xff09;1&#xff09;使用嵌入式数据…

jmc线程转储_查找线程转储中的异常和错误

jmc线程转储线程转储是解决生产问题/调试生产问题的重要工件。 在像过去我们已经讨论了几种有效的线程转储故障模式&#xff1a; 堵车 &#xff0c; 跑步机 &#xff0c; RSI &#xff0c; 一个 LL条条大路通罗马 .........。 在本文中&#xff0c;我们想介绍另一种线程转储故障…

命令模式的两种不同实现

转载自 命令模式&#xff08;Command&#xff09;的两种不同实现命令模式&#xff08;Command&#xff09;&#xff1a;将一个请求封装成一个对象&#xff0c;使得你用不同的请求把客户端参数化&#xff0c;对请求排队或者记录请求日志&#xff0c;可以提供命令的撤销和恢复功能…

tomcat(18)部署器

【0】README-1&#xff09;先上干货&#xff1a;本文重点分析了tomcat 如何部署WAR文件的项目形式 以及 普通文件夹的项目形式&#xff1b;不管是WAR文件 还是 普通文件夹的项目形式&#xff0c;在tomcat中&#xff0c;它们都是Context容器&#xff1b;&#xff08;Bingo&#…

装饰器模式和代理模式的区别

转载自 装饰器模式和代理模式的区别学习AOP时&#xff0c;教材上面都说使用的是动态代理&#xff0c;可是在印象中代理模式一直都是控制访问什么的&#xff0c;怎么又动态增加行为了&#xff0c;动态增加行为不是装饰器模式吗&#xff1f;于是找了很多资料&#xff0c;想弄清楚…

使用Java 8 Stream像操作SQL一样处理数据(上)

转载自 使用Java 8 Stream像操作SQL一样处理数据&#xff08;上&#xff09; 几乎每个Java应用都要创建和处理集合。集合对于很多编程任务来说是一个很基本的需求。举个例子&#xff0c;在银行交易系统中你需要创建一个集合来存储用户的交易请求&#xff0c;然后你需要遍历整个…

tomcat(19)Manager应用程序的servlet类

【0】README1&#xff09;本文部分文字描述转自&#xff1a;“深入剖析tomcat”&#xff0c;旨在学习“tomcat(19)Manager应用程序的servlet类” 的相关知识&#xff1b;2&#xff09;Manager应用程序用来管理已经部署的web 应用程序&#xff1b;在tomcat7中&#xff0c;manage…