#java应用重启脚本#java应用优雅退出#java应用检查脚本

一个优雅退出, 使用15退几次, 不行直接9杀死不就行了嘛

网上博客文章一大堆, bbbb的,没一个讲的明白的, 只有华为云社区, 简书里有些东西还能看的下去; NIMA钩子回调都出来了, 你会为了做一个程序, 去接受linux的信号, 然后再java里System.exit?
你说你是78大公司, 就这样, 会做, 那你把示例贴出来, 让别人用啊, bb半天, 讲半天, 绕的云里雾里的, 最后说, 我已经讲的很清楚了, 你自己去开发写, 睿智zz行为

一堆讲原理的,没一个办实事的! 真实搞笑, 而且一篇文章, 抄来抄去, 复制粘贴下来就是你的了吗?

真是搞笑, 搞不懂做技术的人, 到底是为了做一个健壮的程序, 还是为了平常聊天沟通, 面试的时候装比用的!sb行为

已经做好备注, 仔细阅读即可

使用方式:
- 1, sh server.sh start
- 2, sh server.sh start /data/config/application.properties
- 3, sh server.sh start /data/config/application.properties java_app.jar
- 3,sh server.sh start /data/config/application.properties java_app.jar /data/config

自定义修改
可以自定义修改一些JVM, GC, Spring-Lib等参数, 其他的一般不用动


#!/bin/bash
# sh server.sh start /data/config/application.properties java_app.jar /data/config

DATE=$(date +%Y%m%d%H%M%S)
#FILE_PATH  当前执行的脚本, 全路径, 如:/data/backend/server.sh
FILE_PATH=$(realpath "$0")
#APP_HOME  当前所在的全路径, 如: /data/backend/
APP_HOME=$(dirname "$FILE_PATH")
#############################################可以自定义###############################################################

#设置一些JVM , GC 的参数
#G1 opitons
#JAVA_MEM_OPTS="-server -Xms4g -Xmx4g  -XX:MaxMetaspaceSize=512m -Xss256k -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1ReservePercent=30 -XX:InitiatingHeapOccupancyPercent=30 -XX:ConcGCThreads=4"
#ParallelGC options
JAVA_MEM_OPTS="-server -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
#可以额外加载一些类库
SPRING_LOADER_PATH=$APP_HOME/libs

#JMX="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1091 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"

############################################可以自定义#################################################################
echo
echo
echo "APP_HOME: $APP_HOME"
cd "$APP_HOME" || exit

#如果执行此脚本的时候, 不添加第二个参数, 就去找当前路径下所有的jar文件, 并且执行第一个
#也就是: sh server.sh 没指定其他参数, 就会自动寻找
APP_JAR_NAME=$3
if [ -z "$APP_JAR_NAME" ]; then
  APP_JAR_NAME=$(ls -t -1 | grep .jar$ | head -n1)
fi
JAR_FILE=$APP_HOME/$APP_JAR_NAME

if [ ! -f "$JAR_FILE" ]; then
  echo "jar file path: $JAR_FILE, jar包不存在"
  exit 1
fi
echo "jar file: $JAR_FILE"

#可以直接指定属性文件的文件夹
CONFIG_PATH=$4
if [ -z "$CONFIG_PATH" ]; then
  CONFIG_PATH=$(ls -t -1 | grep .properties$ | head -n1)
fi
if [ -z "$CONFIG_PATH" ]; then
  CONFIG_PATH=$(ls -t -1 | grep .yml$ | head -n1)
fi

CONFIG_PATH=$APP_HOME/$CONFIG_PATH
if [ ! -f "$CONFIG_PATH" ]; then
  echo "config file path: $CONFIG_PATH, 配置文件不存在"
  exit 1
fi

echo "CONFIG_PATH: $CONFIG_PATH"

#截取应用的名字, 为了后续生成日志文件做准备, 比如app.jar会变成 app
SERVER_NAME=$(basename "$APP_JAR_NAME" .jar)
LOG_PATH=$APP_HOME/logs/$SERVER_NAME.outs
GC_LOG_PATH=$APP_HOME/logs/gc-$SERVER_NAME-$DATE.log

mkdir -p "$APP_HOME"/logs

SPRING_BOOT_OPTS="-Dname=$SERVER_NAME -Dspring.config.location=$CONFIG_PATH"
if [ -n "$SPRING_LOADER_PATH" ]; then
  SPRING_BOOT_OPTS="$SPRING_BOOT_OPTS -Dloader.path=$SPRING_LOADER_PATH"
fi
JVM_OPTS="-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Duser.timezone=Asia/Shanghai -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails"
JVM_OPTS="$JAVA_MEM_OPTS $JVM_OPTS $SPRING_BOOT_OPTS $JMX"

echo "SERVER_NAME: $SERVER_NAME"
echo "LOG_PATH: $LOG_PATH"
echo "GC_LOG_PATH: $GC_LOG_PATH"
echo "APP_JAR_NAME: $APP_JAR_NAME"
echo "JVM_OPTS: $JVM_OPTS"
echo
echo

#读取属性文件, 从属性文件里找到server.port的值是多少
function read_property() {
  local file_name=$1
  local property_name=$(echo $2 | sed 's/\./\\\./g')
  cat ${file_name} | sed -n -e "s/^[ ]*//g;/^#/d;s/^$property_name=//p" | tail -1
}

function checkpid() {
  pid=$(ps -ef | grep "$JAR_FILE" | grep -v "grep" | awk '{print $2}')
}

function start() {
  APP_PORT=$(read_property "$CONFIG_PATH" "server.port")

  if [ -z "$APP_PORT" ]; then
    echo "应用端口未设置"
    exit 1
  fi

  LISTEN=$(netstat -an | grep ":$APP_PORT" | grep LISTEN)
  if [ -n "$LISTEN" ]; then
    echo "warn: port $APP_PORT is already used."
    exit 1
  fi

  checkpid
  if [ -z "$pid" ]; then
    STARTTIME=$(date +"%s")

    exec nohup java -jar $JVM_OPTS $JAR_FILE >"$LOG_PATH" 2>&1 &

    echo "---------------------------------"
    echo "应用 $SERVER_NAME (端口: $APP_PORT) 启动中>>>>>"
    echo "---------------------------------"
    sleep 2s

    TIMEOUT=180
    CHECK_STARTUP_URL="http://localhost:$APP_PORT/ok.htm"
    while [ $TIMEOUT -gt 0 ]; do
      RESULT=$(curl --connect-timeout 1 -s $CHECK_STARTUP_URL)
      ENDTIME=$(date +"%s")
      COSTTIME=$(($ENDTIME - $STARTTIME))

      if [ $COSTTIME -ge $TIMEOUT ]; then
        break
      fi

      if [ -z "$RESULT" ]; then
        sleep 1
        echo -n -e "\rWait app $SERVER_NAME to start: $COSTTIME seconds"
        continue
      fi

      COUNT=$(echo "$RESULT" | grep -c -i OK)
      if [ "$COUNT" -ge 1 ]; then
        checkpid
        echo
        echo "App $SERVER_NAME(pid:$pid) started in $COSTTIME seconds."
        return
      else
        echo "ERROR: Start APP $SERVER_NAME Failed!!!"
        exit
      fi
    done

    if [ $COSTTIME -ge $TIMEOUT ]; then
      echo
      echo "App $SERVER_NAME start timeout in $TIMEOUT seconds, may start failed."
      echo "check log files in $LOG_PATH."
    fi
  else
    echo "App $SERVER_NAME(pid:$pid) is running."
  fi
}

function stop() {
  checkpid
  if [ -z "$pid" ]; then
    echo "App $SERVER_NAME is not running."
    exit 1
  fi

  echo "---------------------------------"
  echo "应用 $SERVER_NAME(pid:$pid) 关闭中>>>>>"
  echo "---------------------------------"

  kill $pid
  RETVAL=$?
  checkpid
  TIMEOUT=30
  COSTTIME=1
  while [ $RETVAL = 0 ] && [ $COSTTIME -le $TIMEOUT ] && [ -n "$pid" ]; do
    sleep 1
    echo -n -e "\rWait app $SERVER_NAME(pid:$pid) to stop: $COSTTIME seconds."
    ((COSTTIME++))
    checkpid
  done

  echo
  if [ $COSTTIME -ge $TIMEOUT ]; then
    echo "App $SERVER_NAME stop timeout in $TIMEOUT seconds, force killed."
    kill -9 "$pid" >/dev/null 2>&1
  fi

  echo "App $SERVER_NAME stopped."
}

restart() {
  stop
  sleep 3s
  start
}

status() {
  checkpid
  if [ -n "$pid" ]; then
    echo "App $SERVER_NAME(pid $pid) is running..."
    return 0
  fi
  echo "App $SERVER_NAME is stopped."
}

#查看一下当前时间的一些java程序的信息, 内存, cpu, gc, stack之类的东西
dump() {
  LOGS_DIR=$APP_HOME/logs/
  DUMP_DIR=$LOGS_DIR/dump
  if [ ! -d "$DUMP_DIR" ]; then
    mkdir "$DUMP_DIR"
  fi
  DUMP_DATE=$(date +%Y%m%d%H%M%S)
  DATE_DIR=$DUMP_DIR/$DUMP_DATE
  if [ ! -d "$DATE_DIR" ]; then
    mkdir "$DATE_DIR"
  fi

  echo -e "Dumping the $SERVER_NAME ...\c"

  PIDS=$(ps -ef | grep java | grep "$JAR_FILE" | awk '{print $2}')
  for PID in $PIDS; do
    jstack $PID >$DATE_DIR/jstack-$PID.dump 2>&1
    echo -e "PID=$PID .\c"
    jinfo $PID >$DATE_DIR/jinfo-$PID.dump 2>&1
    echo -e ".\c"
    jstat -gcutil $PID >$DATE_DIR/jstat-gcutil-$PID.dump 2>&1
    echo -e ".\c"
    jstat -gccapacity $PID >$DATE_DIR/jstat-gccapacity-$PID.dump 2>&1
    echo -e ".\c"
    jmap $PID >$DATE_DIR/jmap-$PID.dump 2>&1
    echo -e ".\c"
    jmap -heap $PID >$DATE_DIR/jmap-heap-$PID.dump 2>&1
    echo -e ".\c"
    jmap -histo $PID >$DATE_DIR/jmap-histo-$PID.dump 2>&1
    echo -e ".\c"
    if [ -r /usr/sbin/lsof ]; then
      /usr/sbin/lsof -p $PID >$DATE_DIR/lsof-$PID.dump
      echo -e ".\c"
    fi
  done

  if [ -r /bin/netstat ]; then
    /bin/netstat -an >$DATE_DIR/netstat.dump 2>&1
    echo -e "netstat.dump ..."
  fi
  if [ -r /usr/bin/iostat ]; then
    /usr/bin/iostat >$DATE_DIR/iostat.dump 2>&1
    echo -e "iostat.dump ..."
  fi
  if [ -r /usr/bin/mpstat ]; then
    /usr/bin/mpstat >$DATE_DIR/mpstat.dump 2>&1
    echo -e "mpstat.dump ..."
  fi
  if [ -r /usr/bin/vmstat ]; then
    /usr/bin/vmstat >$DATE_DIR/vmstat.dump 2>&1
    echo -e "vmstat.dump ..."
  fi
  if [ -r /usr/bin/free ]; then
    /usr/bin/free -t >$DATE_DIR/free.dump 2>&1
    echo -e "free.dump ..."
  fi
  if [ -r /usr/bin/sar ]; then
    /usr/bin/sar >$DATE_DIR/sar.dump 2>&1
    echo -e ".\c"
  fi
  if [ -r /usr/bin/uptime ]; then
    /usr/bin/uptime >$DATE_DIR/uptime.dump 2>&1
    echo -e ".\c"
  fi

  echo "OK!"
  echo "DUMP: $DATE_DIR"
}

case $1 in
start)
  start
  ;;
stop)
  stop
  ;;
restart)
  restart
  ;;
status)
  status
  ;;
read)
  read_property
  ;;
dump)
  dump
  ;;
*) echo "require start|stop|restart|status|dump" ;;
esac



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值