linux 自己的java,linux环境中Java服务通过shell脚本重启(升级)自己

今天遇到一个远程升级的需求,通过接口去触发终端服务的接口,重新拉取最新的jar包,并重启终端服务,这个终端服务是用java写的。 实现该需求,两个步骤,一个是需要一个shell脚本:拉取jar包、kill掉服务、启动服务;还有一个就是java中收到消息去调用shell脚本。

脚本

启动命令:

/root/dtest/upgrade.sh jar-name 端口 jar下载地址 jar存放路径

1 # !/bin/bash

2 echo "start upgrade......"

3 ## 判断参数是否正确

4 ########### jar包名称 ############

5 APPLICATION_NAME=""

6 if [ ! $1 ]; then

7 echo "待执行的jar名称 IS NULL"

8 exit 1

9 else

10 APPLICATION_NAME=$1".jar"

11 fi

12 SERVER_PORT=""

13 if [ ! $2 ]; then

14 echo "端口 IS NULL"

15 exit 1

16 else

17 SERVER_PORT=$2

18 fi

19 ########### 软件包下载地址 ############

20 FILE_URL=""

21 if [ ! $3 ]; then

22 echo "软件包下载地址 IS NULL"

23 exit 1

24 else

25 FILE_URL=$3

26 fi

27 BASE_PATH=""

28 if [ ! $4 ]; then

29 echo "软件包下载地址 IS NULL"

30 BASE_PATH="/usr/local/docker"

31 else

32 BASE_PATH=$4

33 fi

34 ## kill 掉进程

35 PROCESS=`ps -ef|grep $APPLICATION_NAME|grep -v grep|grep -v PPID|awk '{ print $2}'`

36 for i in $PROCESS

37 do

38 echo "停止服务:kill the $APPLICATION_NAME process [ $i ]"

39 kill -9 $i

40 done

41 ##备份

42 rm -rf $APPLICATION_NAME

43 ## 下载应用服务包

44 echo "download the application package"

45 echo "升级包下载命令 wget $FILE_URL -O "/root/dtest/"$APPLICATION_NAME"

46 wget $FILE_URL -O "/root/dtest/"$APPLICATION_NAME

47 echo "升级包下载完成!!!"

48 ## 启动服务

49 echo "开始启动 $1 服务"

50 chmod 777 $APPLICATION_NAME

51 nohup java -server -jar -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -Xms256m -Xmx512m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC $BASE_PATH"/"$APPLICATION_NAME --server.port=$SERVER_PORT 2>&1 &

52 echo "服务启动命令:java -server -jar -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -Xms256m -Xmx512m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC $BASE_PATH"/"$APPLICATION_NAME --server.port=$SERVER_PORT > /dev/null 2>&1 &"

53 for st in $(seq 1 20)

54 do

55 # PID=$(netstat -nlp | grep :$EXECUTE_PORT | awk '{print $7}' | awk -F"/" '{ print $1 }');

56 PID=$(netstat -nlp | grep :$SERVER_PORT | awk '{print $7}' |sed 's/\([0-9]*\).*/\1/g');

57 if [ $st -eq 20 ] && [ -z "$PID" ]; then

58 echo "服务启动失败" ### $PID 为空

59 break

60 fi

61

62 if [ -z "$PID" ]; then

63 sleep 2

64 echo $st"服务启动中...." ### $PID 为空

65 else

66 echo "服务名称:$APPLICATION_NAME ,端口号为:$SERVER_PORT ,进程号为:$PID 启动成功 , 耗时:$[$[st-1]*3] seconds!!!"

67 break

68 fi

69 done

Java程序

java调用shell脚本有多种方式,简单粗暴的方式是:Runtime.getRuntime().exec()

但现实给我上了一课,当kill掉自己服务后,后面的脚本也停止执行了,原因处在,当服务执行自身重启的命令时,父进程关闭导致管道连接中断,将导致子进程也崩溃,从而无法完成后续的启动。

解决方式,

设置子进程IO输出重定向到指定文件

设置属性子进程的I/O源或目标将与当前进程的相同,两者相互独立

上代码:(源码下载)

1 package com.dzh.boot.demo.controller;

2

3 import org.springframework.beans.factory.annotation.Value;

4 import org.springframework.web.bind.annotation.RequestMapping;

5 import org.springframework.web.bind.annotation.RestController;

6

7 import java.io.File;

8 import java.io.IOException;

9

10 /**

11 * 升级当前服务 --- 拉取最新jar,杀掉当前服务,启动最新的jar

12 * @date 2021.4.9

13 */

14 @RestController

15 public class UpgradeController {

16

17 //脚本的地址

18 @Value("${my.test.scriptPath}")

19 private String scriptPath;

20

21 /**

22 * jar包的名称 去掉.jar

23 */

24 @Value("${my.test.name}")

25 private String applicationName;

26

27 /**

28 * 服务启动的端口

29 */

30 @Value("${server.port}")

31 private String port;

32

33 /**

34 * 最新jar包的下载地址

35 */

36 @Value("${my.test.fileUrl}")

37 private String fileUrl;

38

39 /**

40 * jar包放置的路径

41 */

42 @Value("${my.test.basePath}")

43 private String basePath;

44

45 /**

46 * 触发升级

47 * @return

48 * @throws Exception

49 */

50 @RequestMapping("run")

51 private String run() throws Exception {

52 ProcessBuilder sh = new ProcessBuilder("sh", scriptPath, applicationName, port, fileUrl, basePath);

53 asynExeLocalComand(null, sh);

54 return "成功";

55 }

56

57 /**

58 * 用来检查服务是否正常

59 * @return

60 * @throws IOException

61 */

62 @RequestMapping("getParam")

63 private String getParam() throws IOException {

64 return scriptPath + " " + applicationName + " " + fileUrl + " " + basePath + " " + port;

65 }

66

67

68

69 public static void asynExeLocalComand(File file, ProcessBuilder pb) throws IOException {

70 // 不使用Runtime.getRuntime().exec(command)的方式,因为无法设置以下特性

71 // Java执行本地命令是启用一个子进程处理,默认情况下子进程与父进程I/O通过管道相连(默认ProcessBuilder.Redirect.PIPE)

72 // 当服务执行自身重启的命令时,父进程关闭导致管道连接中断,将导致子进程也崩溃,从而无法完成后续的启动

73 // 解决方式,(1)设置子进程IO输出重定向到指定文件;(2)设置属性子进程的I/O源或目标将与当前进程的相同,两者相互独立

74 if (file == null || !file.exists()) {

75 // 设置属性子进程的I/O源或目标将与当前进程的相同,两者相互独立

76 pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);

77 pb.redirectError(ProcessBuilder.Redirect.INHERIT);

78 pb.redirectInput(ProcessBuilder.Redirect.INHERIT);

79 } else {

80 // 设置子进程IO输出重定向到指定文件

81 // 错误输出与标准输出,输出到一块

82 pb.redirectErrorStream(true);

83 // 设置输出日志

84 pb.redirectOutput(ProcessBuilder.Redirect.appendTo(file));

85 }

86 // 执行命令进程

87 pb.start();

88 }

89

90 }

标签:shell,Java,NAME,jar,echo,APPLICATION,linux,进程,服务

来源: https://www.cnblogs.com/dingzuoheng/p/14637855.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值