Linux下启动Springboot服务

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Linux下通过编写Shell脚本启动Springboot

1. 背景

springboot

由于实际项目需要,需要在 Linux 下发部署 Java Web 应用。因为此前都是通过 Weblogic来部署的,乍换一种方式,有点不使用。

主要遇到问题有三个:

  • 启动过程有点繁琐,不够简单易用,对维护人员有一定要求,去理解每个参数的设置
  • 而且启动参数,每次重启都要输入一堆参数,不够便捷
  • 再者,重启过程需要找到进程 然后 kill 掉,再重启,耗时多

2. 解决思路

通过网上材料,无非通过 K8S 去管理部署应用 以及 原生 Java 方式管理,但是我们的 K8S 环境还没提供,只能暂时采用 Java 原生。

Java 原生,参数太多,那考虑将这些参数封装成为一个 shell 脚本,以后服务的启动、停、重启或者查看状态,都是通过 一个 shell 脚本来完成。

Shell 脚本功能就是提供应用的 启动、停、重启或者查看状态。那就是写四个方法,分别让用户选择。

3. 实现举措

四个核心方法,完成应用的 启动、停、重启或者查看状态。

3.1. 核心方法


function start()
{

}

function stop()
{
    
}

function restart()
{
    
}

function status()
{

}

3.2. 启动

启动过程中指定 JVM 参数,这里提供参考 JVM_OPTS="-Dname=$SpringBoot -Duser.timezone=Asia/Shanghai -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=768M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"

设置 虚拟机内容、和 内容异常过程中Dump操作、以及设置 GC日志路径。

3.3. 停止

  • 应用停止过程中需要判断应用当前的状态,通过 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' 检查出来应用的 PID 。
  • 通过 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' | xargs kill 来停止应用

3.4. 重启

结合 启动和停止,查询应用状态,服务存在的话,则 kill 应用,然后再启动应用。

3.4.1. 查看状态

应用停止过程中需要判断应用当前的状态,通过 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' 检查出来应用的 PID 。

3.5. 其他

3.5.1. 日志路径

默认在当前应用的目录下构建 logs 日志文件夹,并按照应用名称,分目录存储。

如应用 A,则日志文件在 logs/A/

3.5.2. 格式化日志

利用 function log_* 方法,定义日志的级别。


LOG_LEVEL=1

function log_debug(){
  content="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 1  ] && echo -e "\033[32m"  ${content}  "\033[0m"
}
function log_info(){
  content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 2  ] && echo -e "\033[32m"  ${content} "\033[0m"
}
function log_warn(){
  content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 3  ] && echo -e "\033[33m" ${content} "\033[0m"
}
function log_err(){
  content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 4  ] && echo -e "\033[31m" ${content} "\033[0m"
}
function log_always(){
   content="[ALWAYS] $(date '+%Y-%m-%d %H:%M:%S') $@"
   [ $LOG_LEVEL -le 5  ] && echo -e  "\033[32m" ${content} "\033[0m"
}

4. 完整文件


#!/bin/bash

# 日志级别 debug-1, info-2, warn-3, error-4, always-5
LOG_LEVEL=1

# 调试日志
function log_debug(){
  content="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 1  ] && echo -e "\033[32m"  ${content}  "\033[0m"
}
# 信息日志
function log_info(){
  content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 2  ] && echo -e "\033[32m"  ${content} "\033[0m"
}
# 警告日志
function log_warn(){
  content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 3  ] && echo -e "\033[33m" ${content} "\033[0m"
}
# 错误日志
function log_err(){
  content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $@"
  [ $LOG_LEVEL -le 4  ] && echo -e "\033[31m" ${content} "\033[0m"
}
# 一直都会打印的日志
function log_always(){
   content="[ALWAYS] $(date '+%Y-%m-%d %H:%M:%S') $@"
   [ $LOG_LEVEL -le 5  ] && echo -e  "\033[32m" ${content} "\033[0m"
}


SpringBoot=$1

if [ "$SpringBoot" = "" ];
then
    log_err "Please enter the Jar application name"
    lot=$(find ./ -maxdepth 1 -type f -and -name "*.jar")
    # lot_pat=${lot#*/}
    log_err "The Optional Jar applications are as follows: $lot"
    exit 1
fi

ADATE=$(date +%Y%m%d%H%M%S)

# 启动参数
START_OPTS=$3

# JVM参数
APP_HOME=$(pwd)

dirname $0|grep "^/" >/dev/null


# 获取当前执行路径

if [ $? -eq 0 ];then
     APP_HOME=$(DIR_NAME $0)
else
     dirname $0|grep "^\." >/dev/null
     retval=$?
     if [ $retval -eq 0 ];then
        APP_HOME=$(dirname $0|sed "s#^.#$APP_HOME#")
     else
        APP_HOME=$(dirname $0|sed "s#^#$APP_HOME/#")
     fi
fi

log_info "Current directory is $APP_HOME"

ENV_PORT=${START_OPTS#*=}

ENV_DIR="$APP_HOME/logs"


if [ "$ENV_PORT" = "" ]; then
    log_info "Application Port is Null"
    log_info "$ENV_DIR"
    if [ ! -d "$ENV_DIR"  ];then
        mkdir -p $ENV_DIR
    fi

else
    log_info "Application Port is $ENV_PORT"
    ENV_DIR="$ENV_DIR/$ENV_PORT"
    log_info "$ENV_DIR"
    if [ ! -d "$ENV_DIR"  ];then
        mkdir -p $ENV_DIR
    fi
fi

log_warn " Construct log folder $ENV_DIR"

pid=0

Purpose=$2

# 当没有输入具体,操作,默认为 START ,此时需要用户二次确认,输入 Y|y|YES|Yes 同意操作
# 或者 n|N|NO|no ,不同意重启,直接退出
if [ "$Purpose" = "" ];
    then
        log_err "Operation Name Not Entered : The Default Action Is START !"
        read -p  "Are You Sure?[y/n]:"  sure
        case  $sure  in
            y|Y|Yes|YES)  
                log_warn "You Enter $a"
                log_warn "Prepare to restart the app: $SpringBoot"
                Purpose="start"
                ;;
            n|N|NO|no)
                echo "you enter $a"
                log_warn "Ready To Exit Startup: $SpringBoot"
                exit 1
                ;;
            *)
                echo "error";;
        esac
fi


log_debug "##############################"

log_debug "Java environment variable information"

LOG_PATH=$ENV_DIR/$SpringBoot-$ADATE.log
GC_LOG_PATH=$ENV_DIR/gc-$SpringBoot-$ADATE.log

VSpringBoot=${SpringBoot%%.*}

LOG_DEBUG_PATH=$ENV_DIR/$VSpringBoot/debug.log

log_debug "LOG_DEBUG_PATH is $LOG_DEBUG_PATH"


log_debug "$(java -version)"
log_debug "Startup log  $LOG_PATH"

log_debug "Startup gc log  $GC_LOG_PATH"

JVM_OPTS="-Dname=$SpringBoot -Duser.timezone=Asia/Shanghai -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=768M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"

log_debug "$JVM_OPTS $GC_LOG_PATH"

# 启动项目,如果项目已经启动过,则先 kill 掉原先项目,再启动
function start()
{
    # 检查项目的进程是否存在
    checkPid
    # 
    if [ $pid -ne "0" ]; then
        log_info "Application  $SpringBoot Running... PID:$pid ,Please Stop It"
        # echo -e "\033[31m Application  $SpringBoot Running... PID:$pid ,Please Stop It  \033[0m"
        # Kill the current Process
        killPid
        log_info ".............."
        startFun
    else
        log_info ".............."
        startFun
        log_info ".............."
    fi
}


checkPid()
{
    pid=$(ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}')
    # `ps -aux | grep $SpringBoot | grep 'java -jar'|grep -v grep | awk '{print $2}' | xargs kill`
}

killPid()
{
    log_err "Application PID:$pid is being stopped, Please wait for a while, or fish"
    # echo -e "\033[31m Application PID:$pid is being stopped, Please wait for a while, or fish  \033[0m"
    $(ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' | xargs kill)
    tail -n 10 $LOG_DEBUG_PATH
    sleep 10s
}

startFun()
{
    log_debug "Begin Start $SpringBoot ..."
    # echo -e "\033[32m Begin Start $SpringBoot ...  \033[0m"
    $(java -jar $JVM_OPTS $SpringBoot $START_OPTS > $LOG_PATH 2>&1 &)
    # nohup java -jar $JVM_OPTS $SpringBoot --spring.config.location=file:./application.yml $START_OPTS > $LOG_PATH 2>&1 &
    log_debug "$SpringBoot SUCCESS..."
    #echo -e "\033[32m $SpringBoot SUCCESS...  \033[0m"
    sleep 10s
    tail -n 300 $LOG_PATH

}

function stop()
{
    checkPid
    log_info "Begin Stop Application $SpringBoot"
    # echo "Begin Stop Application $SpringBoot"
    if [ "$pid" -ne "0" ]; then
        log_err "$SpringBoot stop..."
        # echo "$SpringBoot stop..."
        killPid
    else
        log_info "$SpringBoot not running!"
        # echo "$SpringBoot not running!"
    fi

}

function restart()
{
    # stop
    sleep 3s
    start
}

function status()
{
    checkPid
    if [ "$pid" -ne "0" ]; then
        log_info "$SpringBoot not running!"
        #echo "$SpringBoot not running!"    
    else
        log_info "$SpringBoot is running... PID:$pid"
        # echo "$SpringBoot is running... PID:$pid"
    fi
}

case $Purpose in
    start) start;;
    stop) stop;;
    restart) restart;;
    status) status;;
    *) log_info "require start|stop|restart|status"  ;;

esac

5. 使用

sh restart.sh $1 $2 $3

  • $1 : SpringBoot 应用名.jar 必选
  • $2 :操作内容,可空,为空默认为 restart
  • $3 : 其他参数,可空

样例如下:


sh restart.sh cia-codegen.jar

6. 效果图

20220720165706

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
23天前
|
Java Spring
Spring boot 运行服务jar外配置配置文件方式总结
Spring boot 运行服务jar外配置配置文件方式总结
139 0
|
1天前
|
小程序 JavaScript Java
微信小程序+SpringBoot接入后台服务,接口数据来自后端
这篇文章介绍了如何将微信小程序与SpringBoot后端服务进行数据交互,包括后端接口的编写、小程序获取接口数据的方法,以及数据在小程序中的展示。同时,还涉及到了使用Vue搭建后台管理系统,方便数据的查看和管理。
微信小程序+SpringBoot接入后台服务,接口数据来自后端
|
24天前
|
Linux
入职必会-开发环境搭建37-Linux常用操作-Linux服务管理
系统启动以后一直存在且常驻内存没有界面的进程就是服务。Linux系统中的所有服务都保存在下列目录中:/usr/lib/systemd/system,进入该目录就能看到所有的服务。
入职必会-开发环境搭建37-Linux常用操作-Linux服务管理
|
5天前
|
Java Windows
SpringBoot Windows 自启动 - 通过 Windows Service 服务实现
SpringBoot Windows 自启动 - 通过 Windows Service 服务实现
18 2
|
9天前
|
Java 开发者 Spring
"揭秘SpringBoot魔法SPI机制:一键解锁服务扩展新姿势,让你的应用灵活飞天!"
【8月更文挑战第11天】SPI(Service Provider Interface)是Java的服务提供发现机制,用于运行时动态查找和加载服务实现。SpringBoot在其基础上进行了封装和优化,通过`spring.factories`文件提供更集中的配置方式,便于框架扩展和组件替换。本文通过定义接口`HelloService`及其实现类`HelloServiceImpl`,并在`spring.factories`中配置,结合`SpringFactoriesLoader`加载服务,展示了SpringBoot SPI机制的工作流程和优势。
23 5
|
5天前
|
NoSQL Java Linux
springboot+redis+虚拟机 springboot连接linux虚拟机中的redis服务
该博客文章介绍了如何在Spring Boot项目中通过配置和代码实现连接运行在Linux虚拟机上的Redis服务,并提供了详细的步骤和测试结果截图。
springboot+redis+虚拟机 springboot连接linux虚拟机中的redis服务
|
7天前
|
编解码 Linux 数据安全/隐私保护
Linux平台x86_64|aarch64架构如何实现轻量级RTSP服务
为满足在Linux平台(x86_64与aarch64架构)上实现轻量级RTSP服务的需求,我们开发了一套解决方案。该方案通过调用`start_rtsp_server()`函数启动RTSP服务,并设置端口号及认证信息。支持AAC音频和H.264视频编码,可推送纯音频、纯视频或音视频流。此外,还支持X11屏幕采集、部分V4L2摄像头采集、帧率/GOP/码率调整、摄像头设备选择与预览等功能。对于音频采集,支持alsa-lib和libpulse接口。整体设计旨在提供150-400ms的低延迟体验,适用于多种应用场景。
|
13天前
|
存储 网络协议 Linux
Linux 多种方式实现文件共享(四)iSCSI 磁盘共享服务 7
【8月更文挑战第7天】iSCSI技术是一种新储存技术, iSCSI 提供了在 IP 网络封装 SCSI 命令,且以TCP/IP协议传输.
35 5
|
6天前
|
编解码 Linux 开发工具
Linux平台x86_64(麒麟|统信UOS)|aarch64(飞腾)如何实现摄像头|屏幕和麦克风|扬声器采集推送RTMP服务或轻量级RTSP服务
国产化操作系统的发展,减少了外部依赖,更符合国家安全标准,并可提升自主研发能力,促进产业链发展,满足定制开发能力,减少了外部技术封锁的风险,提高了国际竞争力,推动了产业升级。目前大牛直播SDK针对Linux平台x86_64架构和aarch64架构的RTMP推送模块和轻量级RTSP服务模块
|
7天前
|
网络协议 Linux
Linux——Centos8.2如何重启网卡服务
Linux——Centos8.2如何重启网卡服务
20 0