
java应用启动脚本
概述
开发了很多 java 项目,最终启动的时候都要用命令行方式启动,项目逻辑千千万,但启动方式都大同小异,参考了一些开源项目(比如 Nacos)的启动脚本,下面整理了一些我目前正在用的 java 应用启动脚本,也支持 jar 加密成 xjar 后的启动,大家可以参考下面的脚本,改造成适合自己的方式
springboot 应用(支持 jar 和 xjar)
springboot 打包部署压缩包看 springboot 应用打包成部署压缩包(支持 xjar)
部署目录结构
app
|-bin/
|-app-server.sh
|-app.jar
|-app.xjar
|-xjar
|-config/
|-application.yml
|-logs/
|-workspace/
使用方法:
启动 jar:./bin/app-server.sh start
启动 xjar:./bin/app-server.sh start xjar
停止:./bin/app-server.sh stop
重启 jar:./bin/app-server.sh restart
重启 xjar:./bin/app-server.sh restart xjar
app-server.sh
#!/bin/bash
BASE_DIR=`cd "$(dirname "$0")"; pwd`
JAR_FILE=$BASE_DIR/app.jar
XJAR_BIN=$BASE_DIR/xjar
XJAR_FILE=$BASE_DIR/app.xjar
CONFIG_FILE=$BASE_DIR/../config/application.yml
LOG_DIR=$BASE_DIR/../logs/
WORKSPACE=$BASE_DIR/../workspace
cygwin=false
darwin=false
os400=false
case "`uname`" in
CYGWIN*) cygwin=true;;
Darwin*) darwin=true;;
OS400*) os400=true;;
esac
error_exit ()
{
echo "错误: $1 !!"
exit 1
}
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=$HOME/jdk/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/usr/java
[ ! -e "$JAVA_HOME/bin/java" ] && JAVA_HOME=/opt/taobao/java
[ ! -e "$JAVA_HOME/bin/java" ] && unset JAVA_HOME
if [ -z "$JAVA_HOME" ]; then
if $darwin; then
if [ -x '/usr/libexec/java_home' ] ; then
export JAVA_HOME=`/usr/libexec/java_home`
elif [ -d "/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home" ]; then
export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home"
fi
else
JAVA_PATH=`dirname $(readlink -f $(which javac))`
if [ "x$JAVA_PATH" != "x" ]; then
export JAVA_HOME=`dirname $JAVA_PATH 2>/dev/null`
fi
fi
if [ -z "$JAVA_HOME" ]; then
error_exit "本应用需要 jdk 环境,请先安装 jdk 环境并设置 JAVA_HOME 环境变量"
fi
fi
# jdk主版本
JAVA_MAJOR_VERSION=$($JAVA -version 2>&1 | sed -E -n 's/.* version "([0-9]*).*$/\l/p"')
HELP_INFO="
用法: $0 [options]
参数:
-h, --help 帮助信息
start <package-type> 启动服务,type可选jar或xjar,默认是jar
stop 停止服务
restart <package-type> 重启服务,type可选jar或xjar,默认是jar
"
CMD_TYPE="unknown"
START_PACKAGE_TYPE="jar"
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
echo "$HELP_INFO"
exit 0
;;
start)
CMD_TYPE="start"
if [[ -n "$2" ]]; then
START_PACKAGE_TYPE="$2"
else
START_PACKAGE_TYPE="jar"
fi
break
;;
stop)
CMD_TYPE="stop"
break
;;
restart)
CMD_TYPE="restart"
if [[ -n "$2" ]]; then
START_PACKAGE_TYPE="$2"
else
START_PACKAGE_TYPE="jar"
fi
break
;;
*)
error_exit "未知参数: $1"
echo "$HELP_INFO"
exit 1
;;
esac
done
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m"
# (非通用)设置自定义的应用数据保存目录、日志保存目录
# 前提是应用内的logback使用了common.log.path变量,以及应用内使用了workspacePath变量指定的目录作为数据存储目录
# 用 -D 传的参数,application.yml 和 logback.xml内部都能使用
# 比如 ${common.log.path:-./logs/},则尝试从启动名中取值,取不到则设置为 ./logs/
JAVA_OPT="${JAVA_OPT} -Dcommon.log.path=$LOG_DIR -DworkspacePath=$WORKSPACE"
# 先加载jar里面的bootstrap.yml,再加载外部的application.yml
JAVA_ARGS="--spring.config.location=classpath:/bootstrap.yml,file:$CONFIG_FILE"
# 定义logback日志保存位置
JAVA_ARGS="${JAVA_ARGS} --logging.file.path=$LOG_DIR"
if [ "$JAVA_MAJOR_VERSION" -ge "9" ]; then
# jdk9以上,使用-Xlog:gc*设置GC输出配置
JAVA_OPT="${JAVA_OPT} -XLog:gc*:file=${LOG_DIR}/app_gc.log:time,tags:filecount=10:filesize=51200"
else
JAVA_OPT="${JAVA_OPT} -Xloggc:${LOG_DIR}/app_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M"
fi
start ()
{
if [[ "$START_PACKAGE_TYPE" == "jar" ]]; then
if [ ! -f "$JAR_FILE" ]; then
error_exit "未找到jar: $JAR_FILE"
exit 1
else
echo "启动jar: $JAR_FILE"
nohup $JAVA_HOME/bin/java $JAVA_OPTS -jar $JAR_FILE $JAVA_ARGS > /dev/null 2>&1 &
echo $! > $BASE_DIR/app.pid
fi
elif [[ "$START_PACKAGE_TYPE" == "xjar" ]]; then
if [ ! -f "$XJAR_BIN" ]; then
error_exit "未找到xjar执行程序: $XJAR_BIN"
elif [ ! -f "$XJAR_FILE" ]; then
error_exit "未找到xjar: $XJAR_FILE"
else
echo "启动xjar: $XJAR_FILE"
nohup $XJAR_BIN $JAVA_HOME/bin/java $JAVA_OPTS -jar $XJAR_FILE $JAVA_ARGS > /dev/null 2>&1 &
echo $! > $BASE_DIR/app.pid
fi
else
error_exit "未知的启动类型: $START_PACKAGE_TYPE"
fi
}
kill_process ()
{
local PID=$1
# 找子进程
CHILD_PIDS=$(pgrep -P $PID)
if [[ -n "$CHILD_PIDS" ]]; then
echo "子进程: $CHILD_PIDS"
for CHILD_PID in $CHILD_PIDS; do
kill_process $CHILD_PID
done
fi
if ps -p $PID > /dev/null; then
echo "停止进程: $PID"
kill $PID
# 循环检测进程是否已停止
WAITING_TIME=0
while ps -p $PID > /dev/null; do
echo "等待进程停止..."
sleep 1
WAITING_TIME=$((WAITING_TIME + 1))
if [[ WAITING_TIME -ge 10 ]]; then
echo "进程停止超时,强制终止进程: $PID"
kill -9 $PID
break
fi
done
echo "进程已停止"
else
echo "进程已停止或不存在: $PID"
fi
}
stop ()
{
if [[ -f "$BASE_DIR/app.pid" ]]; then
PID=$(cat $BASE_DIR/app.pid)
if ps -p $PID > /dev/null; then
echo "停止进程: $PID"
kill_process $PID
echo "进程已停止"
else
echo "进程已停止或不存在: $PID"
fi
rm -f $BASE_DIR/app.pid
else
echo "未找到进程ID文件: $BASE_DIR/app.pid"
fi
}
restart ()
{
stop
start
}
if [[ "$CMD_TYPE" == "start" ]]; then
start
elif [[ "$CMD_TYPE" == "stop" ]]; then
stop
elif [[ "$CMD_TYPE" == "restart" ]]; then
restart
else
echo "$HELP_INFO"
exit 1
fi
本文是原创文章,采用 CC 4.0 BY-SA 协议,完整转载请注明来自 KK元空间
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果