1.引言

1.1背景问题

一个spring boo应用程序每天定时执行一次。

启动时,内存占用800M,结算后占用6G。

执行后,堆内存实际使用1G,但分配的内存达6G。

调整以下JVM参数,只能降到3G,不确定是否延长了处理时间。

-XX:MaxHeapFreeRatio=10

-XX:MinHeapFreeRatio=10

目标是使程序执行后,能够恢复到接近启动时的内存消耗规模。

通过应用程序和参数调整,没有办法实现目标。

只能重启程序。

1.2概念

程序重启通过是否产生新进程开区分2种方式。

热启动:无新进程产生

冷启动:有新进程产生,原进程结束,新进程启动相同程序的进程,包括相同的参数。

冷启动激发分为内部,外部:

。外部重启:通过操作系统,或者资源管理系统执行cron调度策略

程序执行完毕后即退出,由外部系统按照调度策略激活

。应用程序自启:

有直接和间接两种方式。间接是通过中间程序重启,直接则是在原进程结束时重启自身。

直接方式需要在原程序释放资源完毕后执行,避免可能的端口冲突。

重启进程的命令,参数要与原进程一致,并能在运行时获取。

外部重启可以简单地满足需要。 这里仅从技术实现角度探究其它重启Spring boot程序方式:热启动,冷启动-应用程序自启。

1.3热启动

Spring Boot Actuator:

。在程序结束时调用RestartEndpoint.restart,可以重启,但内存并没有降下来

。另起线程执行RestartEndpoint.restart:未验证 。

REST API方式是一种外部调用方式,内部也是RestartEndpoint实现的. 程序内部没有必要使用

Spring DevTools:

。Spring DevTools有重置应用的能力,只能在开发中使用。但其思想应该可以参考。

Spring DevTools 介绍见https://www.jianshu.com/p/b2d4f83aa777

1.4冷启动

。构造启动命令:优雅的方式,避免平台差异和硬编码

。启动时机:在程序任务成功完成后,资源释放后。 利用Runtime.addShutdownHook。

。委托方式:通过中间程序启动

2.热启动

1.Spring Boot Actuator

Spring Boot Actuator的RestartEndpoint 见参考资料[1].

RestartService.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.restart.RestartEndpoint;
import org.springframework.stereotype.Service;@Service
public class RestartService {
@Autowired
private RestartEndpoint restartEndpoint;public void restartApp() {
restartEndpoint.restart();
}
}

调用: @Autowired private RestartService restartService;

@Override
public void run(String... var) {/// 需要重启时调用restartService.restartApp();
}

application.ymal management: endpoint: restart: enabled: true

pom.xml增加依赖

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-cloud-starter</artifactId><version></version></dependency>--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-context</artifactId><version>2.0.2.RELEASE</version></dependency>

下文是另起线程执行RestartEndpoint的restart的例子。

Call Spring actuator /restart endpoint from Spring boot using a java function

@Autowired
private RestartEndpoint restartEndpoint;...Thread restartThread = new Thread(() -> restartEndpoint.restart());
restartThread.setDaemon(false);
restartThread.start();

文中说会有异常,提示程序启动了一个线程但未终止,可能存在内存泄漏。

另起线程有必要吗?

非要另起线程,如何消除文中所说的异常? ---创建的线程怎么会没有结束呢?

RestartEndpoint的invoke和restart区别? ----invoke是提问者使用的方式.

Thread默认是用户线程还是deamon线程? ----跟父线程相同?

为什么restartThread.setDaemon(false)?

Spring Boot programmatically restart app

1.added dependecies:

compile("org.springframework.boot:spring-boot-starter-actuator")

compile("org.springframework.cloud:spring-cloud-starter:1.2.4.RELEASE")

2.autowired restartEndpoint:

import org.springframework.cloud.context.restart.RestartEndpoint;

....

@Autowired

private RestartEndpoint restartEndpoint;

  1. and invoke:

Thread thread = new Thread(new Runnable() {

@Overridepublic void run() {restartEndpoint.invoke();
}

});

thread.setDaemon(false);

thread.start();

I need new Thread because spring mvc creates daemon threads for each request

访问的场景: 。这里是在处理web请求 。请求处理线程是deamon的,不能在这个线程上执行restart吗? 。spring mvc为每个请求创建deamon线程? ---不是线程池吗? 。这个怎么用的是restartEndpoint.invoke,而不是restart呢?

2.2 REST API

Spring Boot programmatically restart app

 You need to add spring-boot-starter-actuator and Spring cloud dependencies to your application and use /restart endpoint to restart the app. Here is the documentation:For a Spring Boot Actuator application there are some additional management endpoints:POST to /env to update the Environment and rebind @ConfigurationProperties and log levels/refresh for re-loading the boot strap context and refreshing the @RefreshScope beans/restart for closing the ApplicationContext and restarting it (disabled by default)/pause and /resume for calling the Lifecycle methods (stop() and start() on the ApplicationContext)Once done, you can use a REST API call to restart the application (via RestTemplate or curl). This will be cleaner way to restart the app than killing it and re-running it.

3.冷启动

3.1示例

参考资料[2]代码:

在结束程序的位置调用:

Application.restartApplication(()->{});

测试结果如下:

  • 原进程结束,有新进程产生,并且占用了端口,但没有控制台输出(在console和IDE下都看不到新进程的存在),Windows资源管理器中也没有该进程ID的进程
  • 启动Notepad.exe,窗口打开,正常

没有控制台是因为

ProcessBuilder.start和Runtime.exec方法创建一个本机进程,并返回 Process 子类的一个实例。

创建的子进程没有自己的终端或控制台。

对于windows平台,可以采用cmd /c start运行方式使子进程有自己的控制台。

Run java process in windows console from another java process

ProcessBuilder pb = new ProcessBuilder("cmd", "/k", "java", "-jar", "AnotherApp.jar");
pb.start();
// 修改为
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "start", "java", "-jar", "AnotherApp.jar");String cmd[]={"cmd", "/c", "start", "java", "-jar", "AnotherApp.jar"};
Runtime rt=Runtime.getRuntime();
Process p=rt.exec(cmd);

Linux下呢?

---应用关心平台差异不是好事情,为什么java不提供满足此需要的api呢?

**没有必要为了本文初衷去选择这种方案。仅作为技术研究活动进行。 **

3.2委托外部程序

程序结束前,启动另外一个程序,由该程序负责在原程序结束后重新启动。

参考代码: JAVA重启自身程序

https://blog.csdn.net/yushi6310/article/details/78792548/

这种方式也有参考资料[2]代码同样的问题。

冷启动方式有以下问题:

  • 启动的进程没有控制台,输出日志如何处理
  • IDE支持:IDE环境下重启后的情况
  • 跨平台:避免特定平台的代码

所以,冷启动没有理想的方式。 网上的参考代码都是什么应用场景呢?

4参考资料

[1]Programmatically Restarting a Spring Boot Application

https://www.baeldung.com/java-restart-spring-boot-app

[2]Programmatically Restart a Java Application

https://dzone.com/articles/programmatically-restart-java

[3]Spring Boot programmatically restart app

https://stackoverflow.com/questions/45074443/spring-boot-programmatically-restart-app

[4]Understanding Java Process and Java ProcessBuilder

https://www.developer.com/java/data/understanding-java-process-and-java-processbuilder.html

5.参考代码

参考资料[2]代码

       /*** Sun property pointing the main class and its arguments.* Might not be defined on non Hotspot VM implementations.*/public static final String SUN_JAVA_COMMAND = "sun.java.command";/*** Restart the current Java application** @param runBeforeRestart some custom code to be run before restarting* @throws IOException*/public static void restartApplication(Runnable runBeforeRestart) throws IOException {try {// java binaryString java = System.getProperty("java.home") + "/bin/java";// vm argumentsList<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();StringBuffer vmArgsOneLine = new StringBuffer();for (String arg : vmArguments) {// if it's the agent argument : we ignore it otherwise the// address of the old application and the new one will be in conflictif (!arg.contains("-agentlib")) {vmArgsOneLine.append(arg);vmArgsOneLine.append(" ");}}// init the command to execute, add the vm argsfinal StringBuffer cmd = new StringBuffer("\"" + java + "\" " + vmArgsOneLine);// program main and program argumentsString[] mainCommand = System.getProperty(SUN_JAVA_COMMAND).split(" ");// program main is a jarif (mainCommand[0].endsWith(".jar")) {// if it's a jar, add -jar mainJarcmd.append("-jar " + new File(mainCommand[0]).getPath());} else {// else it's a .class, add the classpath and mainClasscmd.append("-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0]);}// finally add program argumentsfor (int i = 1; i < mainCommand.length; i++) {cmd.append(" ");cmd.append(mainCommand[i]);}// execute the command in a shutdown hook, to be sure that all the// resources have been disposed before restarting the applicationRuntime.getRuntime().addShutdownHook(new Thread() {@Overridepublic void run() {try {Runtime.getRuntime().exec(cmd.toString());} catch (Exception e) {e.printStackTrace();}}});// execute some custom code before restartingif (runBeforeRestart != null) {runBeforeRestart.run();}// exitSystem.exit(0);} catch (Exception e) {// something went wrongthrow new IOException("Error while trying to restart the application", e);}}

使用ProcessBuilder

How can I restart a Java application?

https://stackoverflow.com/questions/4159802/how-can-i-restart-a-java-application

public void restartApplication()
{final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";final File currentJar = new File(MyClassInTheJar.class.getProtectionDomain().getCodeSource().getLocation().toURI());/* is it a jar file? */if(!currentJar.getName().endsWith(".jar"))return;/* Build command: java -jar application.jar */final ArrayList<String> command = new ArrayList<String>();command.add(javaBin);command.add("-jar");command.add(currentJar.getPath());final ProcessBuilder builder = new ProcessBuilder(command);builder.start();System.exit(0);
}

获取jar文件路径

    URL url = Application.class.getProtectionDomain().getCodeSource().getLocation();System.out.println(url);

在IDE环境下执行(未打包成jar)

输出: file:/E:/workspace/ybt/ybt-clearing/target/classes/

如果打包后运行,则会有包名内容。

这种方式有限制,未考虑:命令参数,不支持IDE环境运行。 没有参考资料[2]考虑的全面。

重启Java程序的方法相关推荐

  1. 在JAVA语言程序中main_在Java程序main方法中,正确的参数是

    [单选题]下列叙述中,错误的是 [填空题]Access属于()数据库,Access中,不允许在主关键字字段中有重复值或(). [单选题]如下哪些字符串是Java中的标识符? [填空题]常用的基本电量传 ...

  2. linux重启java程序

    这篇文章主要讲解 linux重启java程序 #!/bin/sh jarname='test-1.0' pid=`ps aux | grep $jarname | grep -v grep | awk ...

  3. linux通过定时任务定时关闭和重启java程序

    最近,有一个生产服务器每到早上6.10分的时候总会出现大量的云盘读操作,导致有一个java程序挂机. 初步分析此时云盘大量的读操作并不一定是挂机程序导致的(因为有可能是此时读操作,导致了java程序挂 ...

  4. 【Linux】shell调用Java程序main方法通过crontab定时执行

    来源:https://blog.csdn.net/coolcooldool/article/details/51775105 最近一个项目需要写一个batch定时读取文件往数据库里插入记录,第一次写, ...

  5. 用dos命令行执行java程序的方法

    今天开始学java了,从图书馆借了一本Deitel公司的书,坑爹的是上面还是用命令行运行java程序,没有用任何ide,鉴于有些初学者可能需要这么运行,写一下方法.首先要安装jdk,然后记住安装路径. ...

  6. 如何重启java程序jar包_windows下jar包开机自动重启的步骤

    最近做了很多项目,不同的系统,不同的部署方式,这里做个记录 1.在jar包目录新建一个start.bat  文件,然后写入启动命令 jar -jar XXXX.jar 2.仍然在此目录,新建start ...

  7. python实现程序重启_python实现自动重启本程序的方法

    #!/usr/local/bin/python #-*- coding: UTF-8 -*- ##################################################### ...

  8. LINUX中运行java程序的方法

    要想在linux中运行java的项目需要先将项目打包成war包或者jar包. 其中打包成war包需要将war包部署到tomcat服务器上才能运行.而打包成jar包可以直接使用java命令执行. 在li ...

  9. Java 程序代码优化方法

    性能优化是一个永恒不变的主题,养成良好的编码习惯,能够极大地提高程序的性能.这篇文章整理了 java 开发中性能优化的一些方法.  ArrayList & LinkedList 一个是线性表, ...

最新文章

  1. 掌握4个基本点 不被云计算忽悠
  2. mysql 查询优化器跟踪_3. select语句执行过程-优化器
  3. 比特币经历价格过山车 理财还是乐金所、ppmoney网贷靠谱
  4. 录音文件下载_苹果手机录音常见问题解答
  5. kata_FizzBu​​zz Kata与Java流
  6. Failed to maintain projects LRU cache for dir *********
  7. C语言求一个数的平方根倒数的近似值-一战封神的代码
  8. vc通过编译指令传参_iOS开发你不知道的事编译amp;链接
  9. 缺页异常(Page Faults) 和 Kernel Oops打印调用流程
  10. python mmap_python标准库基础之mmap:内存映射文件
  11. Lion Disk Maker让你一键制作Lion系统安装U盘
  12. Unity 坐标转换
  13. 微信小程序获取并修改app.js中的值
  14. 微信扫一扫(wx.scanQRCode)功能新手可能遇到的问题
  15. luogu2485 [SDOI2011]计算器 poj3243 Clever Y BSGS算法
  16. Element和综合练习
  17. %lf 和 %f 、%ld和%d
  18. Flowable 流程引擎系列文章导读
  19. 会所会员消费管理系统解决方案
  20. Vue软件服务不可用的分析过程及解决方案

热门文章

  1. 小程序获取sessionkey_微信小程序登录并且获取sessionkey详解
  2. macOS - 获取 RSSI/BSSID/SSID
  3. 中国最新一批太行发动机成功
  4. 亿级流量架构,服务器如何扩容?写得太好了
  5. 从此错位(相减)无计算
  6. 掘金量化—Python SDK文档—5.API 介绍(2)
  7. CWDM设备和DWDM设备有什么不同之处?
  8. Kali Linux 系统安装TOP和微劈嗯
  9. python模拟登录百度贴吧_TiebaSign
  10. 2022年长沙护士资格考试综合练习题及答案