问题描述
web应用有一个功能菜单是系统升级,通过调用升级脚本,将新发布的war替换原来的tomcat的webapps下的应用,然后停掉tomcate,再重启tomcate。最初实现就是通过简单的用在web项目中通过Process调用这个upgrade.sh脚本文件的。
但是这种实现方式出现了一个问题:javaweb应用是tomcate,作为upgrade.sh脚本的父进程,当这个upgrade.sh进程试图kill掉父进程并重启的时候,父进程被迫终止后,该子进程也无法继续执行。所以这种方式实现的升级功能总是失败。
解决办法
启动一个小应用,来执行Shell,那么这个应用一直以RMI方式监听来自Java应用的命令,根据相应的命令执行脚本。这样的话,用这个java进程去调用Shell命令杀死tomcate,并重启,以此达到系统升级的目的就不会有问题了。
流程如下:
升级程序代码
注册两个命令一个完成系统升级,一个完成Javaweb应用重启,这两个命令的本质就是调用底层的shell脚本完成相应的功能。
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
public class ToolkitListener {
public static void main(String[] argv) {
Logger logger = Logger.getLogger(ToolkitListener.class);
try {
//初始化log4j
PropertyConfigurator.configure(ClassLoader.getSystemClassLoader().getResource("log4j.properties"));
// 启动RMI注册服务,指定端口为1099 (1099为默认端口)
LocateRegistry.createRegistry(1099);
//重启命令
CmdInterface restartCmd = new CmdOfRestart("restart");
Naming.rebind("restartCmd", restartCmd);
//系统升级命令
CmdInterface upgradeCmd = new CmdOfUpgrade("upgradeCmd");
Naming.rebind("upgradeCmd", upgradeCmd);
logger.info("Sensor ToolkitListener is ready.");
} catch (Exception e) {
logger.error("Sensor ToolkitListener is failed. " , e);
}
}
}
RMI调用
在Javaweb应用中,通过RMI的方式调用对应的对象的脚本执行方法。
public static boolean rmiExecute(String name, String var){
if(name==null){
return false;
}
//调用RMI的升级对象完成升级
log.info("rmi object is "+name+",variable is:"+var);
try {
switch(name){
case "upgradeCmd":
CmdInterface cmdOfUpgrade = (CmdInterface) Naming.lookup("upgradeCmd");
cmdOfUpgrade.setFileName(var);
cmdOfUpgrade.excuteShell();
return true;
case "restartCmd":
CmdInterface CmdOfRestart = (CmdInterface) Naming.lookup("restartCmd");
CmdOfRestart.excuteShell();
return true;
default :
return true;
}
} catch (MalformedURLException e) {
log.error("RMI调用异常",e);;
} catch (RemoteException e) {
log.error("RMI调用异常",e);;
} catch (NotBoundException e) {
log.error("RMI调用异常",e);;
}
return false;
}
升级文件校验
java web应用提供系统升级功能,由用户上传升级包,然后调用脚本完成升级。这个过程中需要对升级包进行校验,当前系统中维护了当前系统版本号和升级补丁版本号,上传升级文件中必须提供升级版本的信息,以及上次升级版本号。
web端在启动升级脚本之前,必须进行升级版本验证,只有当前系统版本和补丁版本与升级包描述的上次升级版本和上次升级补丁版本一致时,才是正确的升级补丁包,才会执行升级。
注意事项
升级脚本必须有足够的执行权限才能保证升级脚本能够正确的被执行,如果是新部署的服务器,可能会出现脚本文件权限不足导致升级执行无效。所以部署项目之后,首先需要修改相关脚本的权限,chmod 777 *给与足够权限,否则可能会互相莫名升级无效的情况。