正文开始前的废话:
这里的程序即包括b/s的web application,也包括standalone的类c/s的java application。
 
为什么要自我重启?
 
场景1:分布式环境中,一般会有很多应用(即包括c/s的java application,又有b/s的web application)部署在不同的环境中,为了管理方便,通常会把一些公用的配置,比如:报警发邮件用的邮箱账号/密码/smtp信息,公用的ftp账号信息,甚至jdbc的连接串信息等,统一放在某个位置(共享的网络存储目录、redis缓存、database、zookeeper、远程service中均可),这样管理起来比较方便。象邮箱账号这些信息还好,各应用订阅配置的变化,发现变化时,如果是spring环境,直接调用applicationContext.refresh(),配置就会重新刷新。但是对于数据源这种特殊配置,就比较难弄了,要考虑连接池中已经连接成功的connection对象,已经通过旧的datasource查出来的数据,跟旧datasource关联的sqlSesstionFactory,Mapper实例等等,要全部换血,很难保证,最好的办法就是让程序重启。
 
场景2:写程序嘛,有隐藏的bug在所难免,绝对零bug的程序还是很罕见的,如果随着程序运行时间的不断增加,程序性能越来越差或假死,需要重启一下,通常需要远程连撞到linux,敲命令kill进程,再重启java application,这对于不熟悉linux的新手管理人员,一来可能比较陌生,二来未必有执行权限,所以通过一个友好的监控管理界面,点击下重启按钮,让指定的程序重启,会更容易让人接受。
 
正文开始:
 
一、程序如何知道自己需要重启?
显然,如果有一个程序,用户想正常关闭的时候,程序又自动重启,如此循环,这就成关不掉的恶意程序了。 
所以,程序应该由单独的进程监听并接收特定的指令,而不影响用户正常关闭程序,思路: 
程序启动时,生成一个唯一的uuid(或其它标识,只要保证全局唯一就行),然后向zookeeper注册一个临时节点。 
比如:
/app/uuid-1
这样监控中心,只要扫描/app下有多少临时节点,就知道当前运行了哪些应用。 
管理员从监控中心希望将某个应用重启时,可以向zookeeper写一个节点
/command/uuid-1 节点的内容,约定为:restart 
应用启动后,监听/command/uuid-1 节点的数据变化,一旦发现有restart的数据内容,即认为收到了重启指令,然后就按下面的处理,自我毁灭,重新投胎转世。
 
 
二、java application的重启 
网上的样例代码:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
String restartCmd = "nohup java -jar xxx.jar";
Thread.sleep(10000);//等10秒,保证分身启动完成后,再关掉自己
logger.debug("程序重启完成!");
} catch (Exception e) {
logger.error("重启失败,原因:", e);
}
}
});
logger.debug("程序准备重启!");
System.exit(0);
可以改进的地方: 
a) sleep(10000) 即等待10秒,等自己的『分身』启动好以后,再把自己的『真身』给杀死。这里的10秒,其实也是拍脑袋定的,如果追求完美的话,理论上讲,只要系统进程中出现了新启动的『分身』,就可以将『真身』人道毁灭了。
 
问题:如果知道『分身』已经启动完成?
答案:java可以获取 jps -l 的输出,知道当前所有的java进程,这样就可以知道指定的应用有没有启动。可以在重启前,获取一次jps -l 的输出,重启后,再执行一次jps -l 的输出,对比二次输出,如果发现多出一个新的指定进程名,就表示『分身』启动完成,可以结束自己。
 
附:java代码获取jps输出
import org.apache.logging.log4j.*;
import java.io.BufferedReader;
import java.io.InputStreamReader; public final class RuntimeUtil { private static Logger logger = LogManager.getLogger(); public static String exec(String command) {
StringBuilder sb = new StringBuilder();
try {
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
process.getOutputStream().close();
reader.close();
process.destroy();
} catch (Exception e) {
logger.error("执行外部命令错误,命令行:" + command, e);
}
return sb.toString();
} public static String jps() {
return exec("jps -l");
}
}

  

b)  java -jar xxx.jar 这里也不太好,一是xxx.jar是字符串,编译期发现不了错误,二是路径是相对路径,就算启动成功了,最终jps显示的进程名是jar,看不出实际对应的是啥程序(详情可参考 设置 java -jar 的进程显示名称 ),可以代码获取当前程序的实际路径
    public static String getJarExecPath(Class clazz) {
String path = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
if (OSUtil.getOSname().equals(OSType.Windows)) {
return path.substring(1);
}
return path;
}

OSUtil代码从这里获取

  

三、 web application的重启
这里只讨论部署在jboss上的解决方案,
这二篇文章中,已经给出了用编码或shell命令来控制jboss的方法,所以web application的按需重启思路就有了:
从监控界面点击『重启』某个web application时,后台代码先将该web application disable掉,然后再重新enable或assign

  

java:如何让程序按要求自行重启?的更多相关文章

  1. zabbix3.0.4关于java服务端程序内存溢出的处理

    关于java服务端程序内存溢出的处理 java服务端程序内存溢出会产生jvm.log文件,此时程序会挂掉,无法正常处理业务,需要重启服务 思路: 当存在jvm.log这个文件的时候则触发clean_j ...

  2. 在IntelliJ IDEA中创建和运行java/scala/spark程序

    本文将分两部分来介绍如何在IntelliJ IDEA中运行Java/Scala/Spark程序: 基本概念介绍 在IntelliJ IDEA中创建和运行java/scala/spark程序 基本概念介 ...

  3. Java 获取小程序openid(基于SpringBoot)

    Java 获取小程序openid(基于SpringBoot) 官方文档 wx.login 1.引入Request封装依赖 <!--Request依赖--> <dependency&g ...

  4. 简单java在线测评程序

    简单java程序在线测评程序 一.前言 大家过年好!今年的第一篇博客啊!家里没有网,到处蹭无线!日子过得真纠结!因为毕设的需求,简单写了一个java程序在线测评程序,当然也可以在本地测试. 二.思路 ...

  5. java编译错误 程序包javax.servlet不存在javax.servlet.*

    java编译错误 程序包javax.servlet不存在javax.servlet.* 编译:javac Servlet.java 出现 软件包 javax.servlet 不存在 软件包javax. ...

  6. 使用IzPack打包JAVA Web应用程序

    使用IzPack打包JAVA Web应用程序步骤如下: 这里使用IzPack-4.3.5 + launch4j-3.1.0-beta1-win32.zip(绿色版)对Web应用程序打包,打包后即可对我 ...

  7. 《疯狂Java:突破程序员基本功的16课》读书笔记-第二章 对象与内存控制

    Java内存管理分为两个方面:内存分配和内存回收.这里的内存分配特指创建Java对象时JVM为该对象在堆内存中所分配的内存空间.内存回收指的是当该Java对象失去引用,变成垃圾时,JVM的垃圾回收机制 ...

  8. 【转】Tomcat中部署java web应用程序

    http://www.blogjava.net/jiafang83/archive/2009/06/02/279644.html 转载:今天给大家介绍怎样在Tomcat5.5.9中部署Java Web ...

  9. 在Tomcat中部署Java Web应用程序

    在Tomcat中部署Java Web应用程序有两种方式:静态部署和动态部署.在下文中$CATALINA_HOME指的是Tomcat根目录. 一.静态部署      静态部署指的是我们在服务器启动之前部 ...

随机推荐

  1. jar 命令 打包装class文件的文件夹

    由于将spring源代码导入到eclipse后,缺少jar包,     所以从maven仓库中下载spring发布的spring-core  jar包. 为了方便理解目录结构,使用tree命令: tr ...

  2. zh-Hans vs.net 通过 管理nuget程序包下载简体中文语言包 zh-cn

    zh-Hans  vs.net 通过 管理nuget程序包下载简体中文语言包 在搜索中输入:zh-hans

  3. 面试题整理:SQL(一)

    1.横纵表转换 A表 Name Course Grade Alex English 80 Alex Chinese 70 Alex Japanese 85 Bob English 75 Bob Chi ...

  4. nodejs学习笔记(2)--Express下安装模版引擎ejs

    成功安装完express后,输入express -help,根据提示安装ejs(如下图): 根据提示-e实现安装ejs,注意此处有坑:之前安装的时候根据教程(node.js开发指南第五章5.2.2节) ...

  5. 玩了一天的Git

    今天的逗比事 Git从学习到使用,也有2个月时间了,一开始也就看看廖雪峰老师的Git教程,跟着做了一遍,感觉非常受用. 遇到一些忘掉的命令,再回去查查也基本都没问题. 但是今天缺遇到了逗比事,回过头来 ...

  6. 哭瞎!360云盘将关停,你的几十T照片和文件该怎么办

    IDO老徐刚得到了一个非常不开心的消息,360云盘将停止个人云盘服务...进行业务转型,在网盘存储.传播内容的合法性和安全性得到彻底解决之前不再考虑恢复,之后转型企业云服务. 而且之前共享的所有资料, ...

  7. 【转发】NPAPI开发详解,Windows版

    NPAPI开发详解,Windows版 9 jiaofeng601, +479 9人支持,来自Meteor.猪爪.hanyuxinting更多 .是非黑白 .Yuan Xulei.hyolin.Andy ...

  8. [MySQL Reference Manual] 5 MySQL 服务管理

    5. MySQL 服务管理 5. MySQL 服务管理 5.1 The Mysql Server 5.2 Mysql 服务日志 5.2.1 选择General query log和slow query ...

  9. SQL Server:统计数据库中每张表的大小

    1. 统计数据库中每张表的大小 1.1 首先执行下面的命令 exec sp_MSforeachtable @command1="sp_spaceused '?'"; 1.2 检测当 ...

  10. 从键盘上输入一个正整数n,请按照以下五行杨辉三角形的显示方式, 输出杨辉三角形的前n行。请采用循环控制语句来实现。

    Scanner sc=new Scanner(System.in); System.out.println("请输入一个正整数:"); int ss=sc.nextInt(); i ...