java:如何让程序按要求自行重启?

正文开始前的废话:

这里的程序即包括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的重启

网上的样例代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

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输出


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

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 的进程显示名称 ),可以代码获取当前程序的实际路径


1

2

3

4

5

6

7

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上的解决方案,

jboss CLI 命令行接口学习(适用JBOSS EAP 6.2+)

Jboss EAP:native management API学习

这二篇文章中,已经给出了用编码或shell命令来控制jboss的方法,所以web application的按需重启思路就有了:

从监控界面点击『重启』某个web application时,后台代码先将该web application disable掉,然后再重新enable或assign

时间: 2025-01-10 03:14:15

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

Java命令行程序构建工具-airline

以前对于开发Java命令行程序,我都是很头大的,命令行程序麻烦的是解析参数,以及一些帮助信息,今天在研究接口测试时偶然发现了一个工具可以让你快速构建命令行程序 github地址 airline 导入jar包 airline jar 在maven仓库里搜索适合你构建系统的语句 代码 我找了个解析har文件的项目,来讲解开发过程 定制自己的命令行 我的命令行以doctorq作为命令,参数为company,命令的完整格式应该为doctorq company XXXXX. @Command(name="

福利贴——爬取美女图片的Java爬虫小程序代码

自己做的一个Java爬虫小程序 废话不多说,先上图. 文件夹命名是用标签缩写,如果大家看得不顺眼可以等下载完成后手动改一下,比如像有强迫症的我一样... 这是挂了一个晚上下载的总大小,不过还有很多因为一些问题没有遍历下载到,而且会产生很多空文件,最下面我附带了一个递归删除空文件夹的小程序代码. 接下来是文件夹内部~ 图片存放位置默认为d:\picture,可在程序中更改,main函数的开头就是,有注释.爬取的网站为http://www.mmonly.cc/,大家有更好的资源网站可以私我. 爬虫源

java实现软件程序开机自动启动和创建程序的桌面快捷方式源代码

一.java实现.exe程序的开机自动启动 1.描述 自己在eclipse编写的java项目用exe4j Wizard打包成一个.exe可执行文件,并让用户可以开机自动启动. 2.步骤 1.   获得本软件中.exe可执行文件的路径 2.   在Windows系统中的开机启动栏存放该.exe可执行文件的快捷方式,即可实现开机自动启动. 3.代码 private void startFolderMethod() { String path = System.getProperty("user.di

java图形用户界面程序

GUI(Graphical User Interface) 定义:一个程序中,用户可以可以看见和与之交流的部分. 支持图形用户界面的两套组件: 1,AWT 2,Swing 建立步骤: 建立容器-建立组件-将组件添加到容器-设置布局 Swing中的重量级容器: 继承自AWT中的Container类,为其他容器和组件提供绘制位置 有JFrame,JDialog,JWindow,JApplet; Swing中的轻量级容器: 继承自Swing类的JComponent,为了方便其他组件的定位 有JPane

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

java编译错误 程序包javax.servlet不存在javax.servlet.* 编译:javac Servlet.java 出现 软件包 javax.servlet 不存在 软件包javax.servlet.http 不存在 等错误 由于servlet和JSP不是Java平台JavaSE(标准版)的一部分,而是Java EE(企业版)的一部分,因此,必须告知编译器servlet的位置. 解决“软件包 javax.servlet不存在”错误的方法: 1. 搜索servlet-api.jar

MVC在Java Web应用程序中的实现

一.MVC简介 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑. Model(模型)是应用程序中用于处理应用程序数据逻辑的部分. 通常模型对象负责在数据库中存取数据. View(视图)是应用程序中处理数据显示的部分. 通常视图是依据模型数据创建的. C

SharePoint自定义程序页面部署 不用重启IIS

SharePoint的部署方式默认是部署WSP包,尤其是有多个前端的时候WSP包的部署显得非常方便和快捷,但是WSP的部署需要重启整个IIS服务会造成SharePoint站点一段时间不能访问.结合自己项目的情况这里我们提出文件对考的方式来替代WSP包的部署.这里有两个地方需要注意: 1. 我们的SharePoint项目不会影响SharePoint内容数据库: 2. IIS不重启,但是SharePoint站点对应的应用程序池会自动回收 这里我们以一个demo来做说明: 如图我们的SharePoin

MVC模式在Java web 应用程序的实现

一.MVC简介 MVC(Model-View-Controller)模型-视图-控制器,最早由Trygve Reenskaug在1978年提出,是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件架构.MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能.除此之外,此模式通过对复杂度的简化,使程序结构更加直观.软件系统通过对自身基本部分分离的同时也赋予了各个基本部分应有的功能. Mode

Android学习笔记(43):Java开发SQLite程序

正如前面一文说的,SQLite多用于嵌入式开发中,但有时为了更方便的编辑数据库文件,我们也常常需要开发在电脑上运行的SQLite程序.这种情况是经常发生的,比如在我们需要把一大批的txt文件中的数据插入到一个数据库中的时候. 还好这是很简单的,所以本文我们来学习如何用Java开发SQLite程序. (1)准备工作 下载sqlite-jdbc-版本号.jar文件,放到jre\lib\ext文件夹.如我的路径是C:\Program Files\Java\jre1.8.0_77\lib\ext. (2