Java工程在Linux中部署

  • Post author:
  • Post category:java




Java工程在Linux中部署

java启动的命令

  • 1.java -jar ${JAR_NAME}
  • 2(推荐).java -cp ${CLASSPATH} ${MAIN_CLASS_PATH}

第一种方式执行时,jar包中必须设置主函数(maven在pom中配置主函数),执行成功后进程名为jar,进程多了进程名不好分辨,不推荐使用。

在我的工作当中,很多人写启动脚本只写java一条命令,这样很不安全,很多不懂代码的运维人员不杀进程就启动,会造成启动多个进程的情况。

启动程序需要注意事项:

  • 设置GC输出日志,方便GC调优
  • 设置dump输出日志,当程序内存溢出时转储的镜像文件,打开工具推荐mat、ha
  • 设置CLASSPATH,除了jar包,程序主目录也要加上
  • java参数

    • -Xms 堆内存初始大小
    • -Xmx 堆内存最大值
    • -Xmn 堆内存年轻代大小
    • -Dlog4j.configuration 设置日志配置文件,注意日志配置文件不要打到jar里面,在外面方便DEBUG调试
  • 使用nohup启动时,除了生成程序日志外,还有nohup日志,建议把nohup日志输出到/dev/null(linux黑洞)
  • 做程序启动是否成功的判断

停止程序需要注意事项:

  • 使用kill pid,建议不要加-9强制停止,否则ShutdownHook不会执行

下面附上我的启动、停止进程的脚本,有重复代码,可以适当修改



startup.sh

#!/bin/sh

# 加载JAVA_HOME环境变量
source /etc/profile
if [[ -z "${JAVA_HOME}" ]]
then
    echo "JAVA_HOME is empty"
    exit 1
fi
JAVA_EXEC=${JAVA_HOME}/bin/java
JPS_EXEC=${JAVA_HOME}/bin/jps

# 当前文件所在目录,这里是相对路径
LOCAL_PATH=`dirname $0`
# 当前文件所在目录转为绝对路径(脚本我放在bin目录下)
LOCAL_PATH=`cd ${LOCAL_PATH}/../;pwd`
# 进程名(main函数类名,也是进程名)
APP_NAME="BootstrapStratup"
# 主函数路径
CLASS_NAME="com.zhysunny.main.${APP_NAME}"
# 日志目录(可以放程序目录下的logs目录,需要和log4j配置的路径一致)
LOG_PATH="/var/log/myapp"
if [[ ! -d ${LOG_PATH} ]]
then
    mkdir -p ${LOG_PATH}
fi

# 保留gc日志文件(用于生成GC日志,启动时保留上一次的GC日志)
GC_FILE="${LOG_PATH}/gc.${APP_NAME}.log"
GC_LOG_OPTS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:${GC_FILE} "
if [[ -e ${GC_FILE} ]]
then
    mv ${GC_FILE} ${LOG_PATH}/gc.${APP_NAME}_$(date +"%Y%m%d").log  #重启程序会重置这个文件,这里做个保留
fi

# 保留hprof文件(当程序内存溢出生成dump日志,启动时保留上一次的dump日志)
DUMP_FILE="${LOG_PATH}/zhysunny-${APP_NAME}.hprof "
DUMP_LOG_OPTS="-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${DUMP_FILE} "
if [[ -e ${DUMP_FILE} ]]
then
    mv ${DUMP_FILE} ${LOG_PATH}/zhysunny-${APP_NAME}_$(date +"%Y%m%d").hprof  #重启程序这个文件无法覆盖,这里要重命名
fi

# 设置 classpath
# 注意必须保留环境变量中的CLASSPATH值
# 其次把LOCAL_PATH也作为classpath
# 然后添加所有依赖包,不能用通配符,只能循环
CLASSPATH=${CLASSPATH}:${LOCAL_PATH}
for f in ${LOCAL_PATH}/fss-*.jar; do
    CLASSPATH=${CLASSPATH}:${f}
done

for f in ${LOCAL_PATH}/lib/*.jar; do
    CLASSPATH=${CLASSPATH}:${f}
done

# java 参数
# -Xms 堆内存初始大小
# -Xmx 堆内存最大值
# -Xmn 堆内存年轻代大小
# -Dlog4j.configuration 设置日志配置文件
JAVA_OPTS="-Xmx4g -Xms4g -Xmn3g -Dlog4j.configuration=file:${LOCAL_PATH}/conf/log4j.xml "${GC_LOG_OPTS}${DUMP_LOG_OPTS}
# 启动进程
function startup() {
    # pid可以写入一个文件中
    PID=`${JPS_EXEC} | grep -v "grep" | grep ${APP_NAME} | awk '{print $1}'`
    if [[ -z "${PID}" ]]
    then
        # &可以理解为shell中的并行,nohup之后需要程序终止才能走下一步,这里需要并行
        {
        nohup ${JAVA_EXEC} ${JAVA_OPTS} -classpath ${CLASSPATH} ${CLASS_NAME} ${HDFS_FSS_URL} 1>/dev/null 2>${LOG_PATH}/kafka-es-error.out
        }&
    else
        echo "${APP_NAME} running as process ${PID}.Stop it first."
        exit 1
    fi
    #判断程序是否启动
    i=0
    while((i<10))
    do
        PID=`${JPS_EXEC} | grep -v "grep" | grep ${APP_NAME} | awk '{print $1}'`
        if [[ -z "${PID}" ]]
        then
            sleep 1s
            i=$(($i+1))
        else
            echo "Starting ${APP_NAME} success as process ${PID}"
            break
        fi
    done
    PID=`${JPS_EXEC} | grep -v "grep" | grep ${APP_NAME} | awk '{print $1}'`
    if [[ -z "${PID}" ]]
    then
        echo "Starting ${APP_NAME} failed!"
        exit 1
    fi
}

# 必须先写function,这里才能调用方法
startup

# 结束掉当前shell脚本
kill -2 $$
exit 0



shutdown.sh

#!/bin/sh

# 加载JAVA_HOME环境变量
source /etc/profile
if [[ -z "${JAVA_HOME}" ]]
then
    echo "JAVA_HOME is empty"
    exit 1
fi
JAVA_EXEC=${JAVA_HOME}/bin/java
JPS_EXEC=${JAVA_HOME}/bin/jps

# 当前文件所在目录,这里是相对路径
LOCAL_PATH=`dirname $0`
# 当前文件所在目录转为绝对路径(脚本我放在bin目录下)
LOCAL_PATH=`cd ${LOCAL_PATH}/../;pwd`
# 进程名(main函数类名,也是进程名)
APP_NAME="BootstrapStratup"
# 主函数路径
CLASS_NAME="com.zhysunny.main.${APP_NAME}"

# 开始杀掉进程
PID=`${JPS_EXEC} | grep -v "grep" | grep ${APP_NAME} | awk '{print $1}'`
if [[ -z "${PID}" ]]
then
    echo "${APP_NAME} is not running"
else
    kill ${PID}
    echo "Stopping ${APP_NAME} success"
fi

kill -2 $$
exit 0



版权声明:本文为yezi1238原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。