重启Java程序的方法
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;
- 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程序的方法相关推荐
- 在JAVA语言程序中main_在Java程序main方法中,正确的参数是
[单选题]下列叙述中,错误的是 [填空题]Access属于()数据库,Access中,不允许在主关键字字段中有重复值或(). [单选题]如下哪些字符串是Java中的标识符? [填空题]常用的基本电量传 ...
- linux重启java程序
这篇文章主要讲解 linux重启java程序 #!/bin/sh jarname='test-1.0' pid=`ps aux | grep $jarname | grep -v grep | awk ...
- linux通过定时任务定时关闭和重启java程序
最近,有一个生产服务器每到早上6.10分的时候总会出现大量的云盘读操作,导致有一个java程序挂机. 初步分析此时云盘大量的读操作并不一定是挂机程序导致的(因为有可能是此时读操作,导致了java程序挂 ...
- 【Linux】shell调用Java程序main方法通过crontab定时执行
来源:https://blog.csdn.net/coolcooldool/article/details/51775105 最近一个项目需要写一个batch定时读取文件往数据库里插入记录,第一次写, ...
- 用dos命令行执行java程序的方法
今天开始学java了,从图书馆借了一本Deitel公司的书,坑爹的是上面还是用命令行运行java程序,没有用任何ide,鉴于有些初学者可能需要这么运行,写一下方法.首先要安装jdk,然后记住安装路径. ...
- 如何重启java程序jar包_windows下jar包开机自动重启的步骤
最近做了很多项目,不同的系统,不同的部署方式,这里做个记录 1.在jar包目录新建一个start.bat 文件,然后写入启动命令 jar -jar XXXX.jar 2.仍然在此目录,新建start ...
- python实现程序重启_python实现自动重启本程序的方法
#!/usr/local/bin/python #-*- coding: UTF-8 -*- ##################################################### ...
- LINUX中运行java程序的方法
要想在linux中运行java的项目需要先将项目打包成war包或者jar包. 其中打包成war包需要将war包部署到tomcat服务器上才能运行.而打包成jar包可以直接使用java命令执行. 在li ...
- Java 程序代码优化方法
性能优化是一个永恒不变的主题,养成良好的编码习惯,能够极大地提高程序的性能.这篇文章整理了 java 开发中性能优化的一些方法. ArrayList & LinkedList 一个是线性表, ...
最新文章
- 掌握4个基本点 不被云计算忽悠
- mysql 查询优化器跟踪_3. select语句执行过程-优化器
- 比特币经历价格过山车 理财还是乐金所、ppmoney网贷靠谱
- 录音文件下载_苹果手机录音常见问题解答
- kata_FizzBu​​zz Kata与Java流
- Failed to maintain projects LRU cache for dir *********
- C语言求一个数的平方根倒数的近似值-一战封神的代码
- vc通过编译指令传参_iOS开发你不知道的事编译amp;链接
- 缺页异常(Page Faults) 和 Kernel Oops打印调用流程
- python mmap_python标准库基础之mmap:内存映射文件
- Lion Disk Maker让你一键制作Lion系统安装U盘
- Unity 坐标转换
- 微信小程序获取并修改app.js中的值
- 微信扫一扫(wx.scanQRCode)功能新手可能遇到的问题
- luogu2485 [SDOI2011]计算器 poj3243 Clever Y BSGS算法
- Element和综合练习
- %lf 和 %f 、%ld和%d
- Flowable 流程引擎系列文章导读
- 会所会员消费管理系统解决方案
- Vue软件服务不可用的分析过程及解决方案