Shell脚本启动Java程序

Shell脚本

简介

Shell Script ,Shell脚本与Windows/Dos下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比Windows下的批处理更强大,比用其他编程程序编辑的程序效率更高,它使用了Linux/Unix下的命令。

概念区别

​ shell和shell脚本有什么区别?确切一点说,Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。 Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言(就是你所说的shell脚本)。作为命令语言,它互动式地解释和执行用户输入的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环和分支。它虽然不是 Linux系统内核的一部分,但它调用了系统内核的大部分功能来执行程序、创建文档并以并行的方式协调各个程序的运行。

脚本使用

​ 在实际部署环境下因为每个jar包对于不同环境下使用脚本启动会加快速度,例如使用一个reload命令 他的作用是先停止旧包 将旧包名改名为xxxx-日期.jar 作为备份 然后启动新包,做到一个命令执行 停止-备份-启动,减低了部署难度提高了效率。

JDK环境部署

离线安装包下载

JDK环境一键安装

安装教程

  1. 下载后得到7z压缩包.

  2. 解压到自己想要安装到的目录,本人解压到/home/jdk

    1
    mkdir /home/docker
  3. 进入目录赋权

    1
    2
    cd /home/docker
    chmod +x ./*
  4. 执行安装脚本

    1
    ./install.sh

    成功图

操作Jar包程序

脚本内容

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#要启动的jar名称
App=test
AppName=$App.jar
#原始包名称 用于新老包交替使用
AppSourceName=test-admin.jar
# jar包存放路径
AppPath=/home/test/
# JVM参数
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms256m -Xmx512m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
APP_HOME=`pwd`
LOG_PATH=$APP_HOME/logs/$AppName.log

if [ "$1" = "" ];
then
echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
exit 1
fi

if [ "$AppName" = "" ];
then
echo -e "\033[0;31m 未输入应用名 \033[0m"
exit 1
fi

function start()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`

if [ x"$PID" != x"" ]; then
echo "$AppName is running..."
else
nohup java $JVM_OPTS -jar $AppPath$AppName > output.log 2>&1 &
echo "Start $AppName success..."
fi
}

function stop()
{
echo "Stop $AppName"

PID=""
query(){
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
}

query
if [ x"$PID" != x"" ]; then
kill -TERM $PID
echo "$AppName (pid:$PID) exiting..."
while [ x"$PID" != x"" ]
do
sleep 1
query
done
echo "$AppName exited."
else
echo "$AppName already stopped."
fi
}

function restart()
{
stop
sleep 2
start
}

function reload()
{

stop
sleep 2
TIME=""
TIME=$(date "+%Y-%m%d-%H%M")
NEWFILENAME=$App"-"$TIME".jar"
OLDFILESTAT=`mv ./$AppName ./$NEWFILENAME`

STARFILESTAT=`mv ./$AppSourceName ./$AppName`
start
echo "$NEWFILENAME already reload."


}
function status()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
if [ $PID != 0 ];then
echo "$AppName is running..."
else
echo "$AppName is not running..."
fi
}

case $1 in
start)
start;;
stop)
stop;;
restart)
restart;;
status)
status;;
reload)
reload;;
*)

esac

具体方法解释

启动(start)

1
2
3
4
5
6
7
8
9
10
11
function start()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`

if [ x"$PID" != x"" ]; then
echo "$AppName is running..."
else
nohup java $JVM_OPTS -jar $AppPath$AppName > output.log 2>&1 &
echo "Start $AppName success..."
fi
}

此方法先去查询是否已经启动,存在打印 $AppName is running.. ,不存在则nohup 后台启动 JVM_OPTS中可配置优化配置 比如对于cloud项目 可修改其中nacos配置,提供的代码中写死了生成 output.log文件,但这里其实应该是 /dev/null 搭配 logback.xml 生成日志。

1
2
3
4
5
6
7
8
#nacos 配置
-Dspring.cloud.nacos.discovery.server-addr=10.10.10.10:8848
-Dspring.cloud.nacos.discovery.namespace=123-123-123-123
-Dspring.cloud.nacos.discovery.group=test
-Dspring.cloud.nacos.config.server-addr=10.10.10.10:8848
-Dspring.cloud.nacos.config.namespace=123-123-123-123
#搭配logback
nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 &
1
2
3
4
# 赋权
chmod +x ./test-admin.sh
# start 启动
/test-admin.sh start

停止(stop)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function stop()
{
echo "Stop $AppName"

PID=""
query(){
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
}

query
if [ x"$PID" != x"" ]; then
kill -TERM $PID
echo "$AppName (pid:$PID) exiting..."
while [ x"$PID" != x"" ]
do
sleep 1
query
done
echo "$AppName exited."
else
echo "$AppName already stopped."
fi
}

此方法内部定义了一个query方法查询是否已经启动,不存在打印 $AppName already stopped. ,存在进行kill 关闭并递归再次query

1
2
3
4
# 赋权
chmod +x ./test-admin.sh
# start 启动
/test-admin.sh stop

重启(restart)

1
2
3
4
5
6
function restart()
{
stop
sleep 2
start
}

此方法先执行stop方法,延时2ms 执行启动方法

1
2
3
4
# 赋权
chmod +x ./test-admin.sh
# start 启动
/test-admin.sh restart

重载(reload)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

function reload()
{

stop
sleep 2
TIME=""
TIME=$(date "+%Y-%m%d-%H%M")
NEWFILENAME=$App"-"$TIME".jar"
OLDFILESTAT=`mv ./$AppName ./$NEWFILENAME`
STARFILESTAT=`mv ./$AppSourceName ./$AppName`
start
echo "$NEWFILENAME already reload."

}

此方法先去执行停止方法,延时2ms后获取当前时间 修改旧包名,将新包改名后执行启动方法。例如定义启动的jar(AppName)为test.jar 上传一个名(AppSourceName)为admin的包 ,执行reload方法后 会剩余一个test-2024-08141050.jar和一个test.jar

执行前

执行后

1
2
3
4
# 赋权
chmod +x ./test-admin.sh
# start 启动
/test-admin.sh reload

查状态(status)

1
2
3
4
5
6
7
8
9
function status()
{
PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
if [ $PID != 0 ];then
echo "$AppName is running..."
else
echo "$AppName is not running..."
fi
}

此方法先去查询jar包状态打印是否启动。

1
2
3
4
# 赋权
chmod +x ./test-admin.sh
# start 启动
/test-admin.sh status

开机自启

简介

经常碰到机器断电之后需要重启一大堆服务,为了防止这种事情发生,设置开机自启的脚本十分的重要,我们习惯性的做法就是编写一个重启脚本,然后在 /etc/rc.local 中去完成开机执行。例如下面这样:

1
2
$ cat /etc/rc.local
bash /root/script/restart.sh

注意 如果是自启动上述的脚本,要注意比如jar包、写死的log日志最好都是写全路径

这样的方法虽然可行,但并不优雅。今天我们就给大家介绍两种更好的实现方式:

通过 Crontab 实现

Crontab 可以使用 @reboot 来执行主机启动之后的命令。首先在命令行输入:

1
$ crontab -e

然后添加以下内容:

1
@reboot /home/test/test-admin.sh start

完成后,这个脚本就可以在重启的时候自动执行了。

其它的一些进阶玩法:

在启动完成后的指定时间内运行脚本

1
2
# 在启动 5 分钟后运行指定脚本
@reboot sleep 300 && /home/test/test-admin.sh start

通过 Systemd 实现

首先编写一个名为 restart 的 Systemd 服务:

1
2
3
4
5
6
7
8
9
10
11
$ vim /lib/systemd/system/restart.service

[Unit]
Description=restart
After=default.target

[Service]
ExecStart=/home/test/test-admin.sh start

[Install]
WantedBy=default.target

然后启用这个 Systemd 服务:

1
2
$ systemctl daemon-reload
$ systemctl enable restart.service

完成后,这个服务对应的脚本就可以自动开机自启了。