• springboot项目如何打包成.sh脚本形式运行|assemly插件打包自定义脚本参数


    0. 引言

    springboot作为目前主流的java开发框架,因为便捷和易上手的特性,深受开发者欢迎。springboot默认以jar包形式,通过java -jar指令运行

    但这样的启动方式实际上不是很友好,我们常常看到各类组建通过bin目录下的start.sh脚本进行启动,我们可以在.sh脚本中书写自定义各类启动参数。这样的方式更加友好,那么我们的springboot项目可不可以打包成这样的形式启动呢?

    当然可以,今天我们就来看如何实现

    1. assembly-plugin插件

    assembly是一个maven插件,专门用于maven项目打包。它的作用就是可以将项目打包成一个可以通过脚本文件启动的项目包

    其打包后的项目文件结构如下:

    bin 项目启动/停止/重启等脚本文件目录
    conf 配置文件目录
    lib 依赖包目录

    assembly插件需要配置一个.xml配置文件来指定打包设置。该文件常见的标签配置如下:

    • id: 标识符,添加到打包文件名称的后缀符
      如果设置为${project.version}则会将项目版本号添加到打包文件名中
    • formats:打包格式,支持zip、tar、tar.gz (or tgz)、tar.bz2 (or tbz2)、jar、dir、war等格式,可以同时指定多种打包形式,通过format标签指定
    <formats>
    	<format>tar.gzformat>
       <format>jarformat>
    formats>
    
    • 1
    • 2
    • 3
    • 4
    • includeBaseDirectory 是否包含打包层目录,当设置false时,所有文件直接打包到根目录下;为true时,打包到${artifactId}目录下
    • dependencySets 设置项目依赖包打包的目录
    • fileSets 设置要包含的文件集,可以定义多个fileSet,单个fileSet标签中又包含如下子标签
      directory:要打包的文件夹
      outputDirectory:打包出来的文件夹,比如为bin,则表示将directory文件夹下的文本打包到bin目录下
      includes: 指定要包含(include)或排除(exclude)的打包文件
      fileMode:指定文件权限,权限的指定参考linux系统文件权限,比较常用的0755,0644。我们在文末单独讲解
      directoryMode:指定目录权限
    <fileSet>
        <directory>src/main/assembly/bindirectory>
        <outputDirectory>binoutputDirectory>
        <includes>
           <include>start.shinclude>
           <include>stop.shinclude>
        includes>
        <fileMode>0755fileMode>
    fileSet>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2. 实操

    1、首先我们先创建一个springboot项目assembly-plugin-demo,并且引入spring web依赖,模拟一个web项目

    <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    2、创建一个HelloController,并书写一个简单的接口,用于模拟接口

    /**
     * @author benjamin_5
     * @Description
     * @date 2022/8/27
     */
    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        public String hello(){
            return "hello~~";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3、在项目src/main下创建bin目录,并声明启动/停止/重启脚本

    启动脚本 start.sh

    #!/usr/bin/env bash
    
    #source $(dirname $0)/../../env.sh
    # 进入当前文件目录
    cd `dirname $0`
    # 返回上一级
    cd ..
    
    # jar包名称
    #SERVER_JAR="$SERVER_NAME-$PROJECT_VERSION.jar"
    SERVER_JAR="assembly_plugin_demo-0.0.1-SNAPSHOT.jar"
    BASE_DIR=`pwd`
    
    # 获取java路径
    if [ "$JAVA_HOME" != "" ]; then
     JAVA="$JAVA_HOME/bin/java"
    else
     JAVA=java
    fi
    
    # 指定日志输出路径
    LOGS_DIR=""
    if [ -n "$LOGS_FILE" ]; then
        LOGS_DIR=`dirname $LOGS_FILE`
    else
        LOGS_DIR=$BASE_DIR/logs
    fi
    if [ ! -d $LOGS_DIR ]; then
        mkdir $LOGS_DIR
    fi
    STDOUT_FILE=$LOGS_DIR/stdout.log
    
    # 设置jvm参数
    JAVA_OPTS="-server -Xms1G -Xmx2G -Xmn256m -Xss1m \
    -XX:SurvivorRatio=4 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection \
    -XX:CMSInitiatingOccupancyFraction=60 -XX:+PrintGCDateStamps \
    -XX:+PrintGCDetails -Xloggc:$LOGS_DIR/gc.log"
    
    # 如果项目已经启动则之前停止项目
    echo -n "Starting server ..."
     PID=$(ps -ef | grep $SERVER_JAR | grep -v grep |awk '{print $2}')
    if [ -z "$PID" ]; then
     echo Application is already stopped
    else
     echo kill $PID
     kill -9 $PID
    fi
    
    # 以指定参数启动项目
    nohup $JAVA $JAVA_OPTS $JAVA_DEBUG_OPT -jar lib/$SERVER_JAR > $STDOUT_FILE 2>&1 &
    
    if [ $? -eq 0 ];then
     # echo -n $! > "$PIDFILE"
     if [ $? -eq 0 ]
     then
     sleep 1
     echo STARTED
     else
     echo FAILED TO WRITE PID
     exit 1
     fi
    else
     echo SERVER DID NOT START
     exit 1
    fi
    
    PID_NOW=`ps -ef | grep java | grep -v grep | grep "$SERVER_JAR" | awk '{print $2}'`
    # 打印参数
    echo "进程ID: $PID_NOW"
    echo "输出日志:$STDOUT_FILE"
    
    
    • 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

    停止脚本 stop.sh

    #!/usr/bin/env bash
    
    # jar包名称
    SERVER_JAR="assembly_plugin_demo-0.0.1-SNAPSHOT.jar"
    
    # 停止项目
    echo -n "Stopping server ..."
        PID=$(ps -ef | grep $SERVER_JAR | grep -v grep |awk '{print $2}')
    if [ -z "$PID" ]; then
      echo Application is already stopped
    else
      echo kill $PID
      kill -9 $PID
    fi
    exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4、然后我们在项目的src/main目录下创建一个assembly目录,并且创建一个assembly插件的配置文件assembly.xml

    我们需要在assembly.xml配置文件中申明bin,conf,lib三个路径

    <assembly>
    	<id>assemblyid>
    	<formats>
    		<format>tar.gzformat>
    	formats>
    	<includeBaseDirectory>trueincludeBaseDirectory>
    	<fileSets>
    		<fileSet>
    			<directory>src/main/assembly/bindirectory>
    			<outputDirectory>binoutputDirectory>
    			<fileMode>0755fileMode>
    		fileSet>
    		<fileSet>
    			<directory>src/main/resourcesdirectory>
    			<outputDirectory>confoutputDirectory>
    			<fileMode>0644fileMode>
    		fileSet>
    	fileSets>
    	
    	<dependencySets>
    		<dependencySet>
    			<outputDirectory>liboutputDirectory>
    		dependencySet>
    	dependencySets>
    assembly>
    
    • 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

    在这里插入图片描述

    5、其次我们在pom.xml中引入assembly-plugin插件

    <plugin>
        <artifactId>maven-assembly-pluginartifactId>
        <configuration>
        <descriptor>src/main/assembly/assembly.xmldescriptor>
        configuration>
        <executions>
            <execution>
                 <id>make-assemblyid>
                 <phase>packagephase>
                 <goals>
                     <goal>singlegoal>
                 goals>
             execution>
        executions>
    plugin>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6、重新加载pom文件,下载assembly插件

    7、执行打包指令

    在这里插入图片描述

    出现BUILD SUCCESS说明打包成功

    在这里插入图片描述

    8、打包文件输出在target目录下,如果有指定输出目录,则在输出目录中查找

    在这里插入图片描述

    9、我们将打包出来的’.tar.gz’压缩包文件解压,可以看到其结构就是我们上述指定的bin、conf、lib目录

    在这里插入图片描述

    10、进入bin目录,执行start.sh指令启动项目

    ./start.sh
    
    • 1

    在这里插入图片描述

    11、我们已经将输出内容指定到logs目录下的stdout.log,我们可以通过该日志查看启动明细

    如果启动失败,也可以通过该日志文件查看报错明细。同时也指定了gc日志gc.log,可以通过该文件查看gc详情

    在这里插入图片描述
    12、从上述日志看启动成功了,我们通过访问之前定义的接口来测试

    可以看到正常输出了接口数据,证明我们打包并启动成功了

    在这里插入图片描述

    如上,我们的springboot就成功打包成了bin目录启动形式。

    2.1 优化【未完善】

    上述打包程序并不是最佳的,因为我们的项目的jar包名称是在start.sh脚本中写死的,如果版本升级,或者复用到其他模块中时,就需要修改脚本了,非常的不方便

    所以我们做出优化,希望能够自动获取这个jar包名称

    可以看到我们的jar包名称是:assembly_plugin_demo-0.0.1-SNAPSHOT.jar

    这个名称由两部分组成:服务名,版本号

    于是我们就要想办法获取这两个属性

    1、首先服务名直接在application.properties配置文件中通过spring.application.name属性获取。

    2、配置文件是会一起打包到conf文件夹下的,但我们怎么在shell脚本中获取配置文件中的指定配置项呢?

    答案是可以通过sed指令,如下所示

    PROJECT_VERSION=`sed '/^project.version=/!d;s/.*=//' conf/application.properties`
    
    • 1

    3、其次就是版本号,我们知道版本号是定义在pom.xml文件中的,打包后是没有pom文件的,那么我们的思路就是在application.properties配置文件中获取到版本号

    这里就要考验大家的springboot知识积累了,如何在配置文件中获取到pom属性呢?

    4、首先我们要在pom.xml文件中,添加resource标签,设置filtering=true,让配置文件可以读取pom属性

    <build>
    	<resources>
                <resource>
                    <directory>src/main/resourcesdirectory>
                    <filtering>truefiltering>
                resource>
    	resources>
    build>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5、设置完成后记得重新加载pom文件!!!

    6、然后在application,properties配置文件中通过@xxx@获取pom属性"project.version"

    application.version=@project.version@
    
    • 1

    7、在start.sh脚本中再声明版本号和jar包名变量

    PROJECT_VERSION=`sed '/^application.version=/!d;s/.*=//' conf/application.properties`
    SERVER_JAR="$SERVER_NAME-$PROJECT_VERSION.jar"
    
    • 1
    • 2

    8、重新打包即可,stop.sh脚本中处理类似

    9、这里存在一个问题尚未解决,上述说的@xxx@的方式读取pom属性,在idea中打包,可以看到本身的打包插件已经加载了pom中的属性,如下图

    在这里插入图片描述

    但是assembly插件打包的conf目录中的配置文件中却没能加载pom的值,初步怀疑是加载顺序的问题,仍在研究中,这里也抛出问题点,大家一起讨论解决。有思路的同学,可以留言讨论

    在这里插入图片描述

    演示代码见文末

    3. 补充内容

    fileMode/directoryMode权限

    assembly中的权限表示与linux系统一致,通过4位数值表示权限

    其中第一位0表示采用十进制,第二位表示用户权限,第三位组用户权限,第四位表示其他用户权限,而十进制表示的权限等级如下:

    十进制linux权限说明
    0无任何权限
    1–x执行权限
    2–w可写权限
    3-wx可写、执行权限
    4r–只读权限
    5r-x可读、可执行权限
    6rw-读写权限
    7rwx全部权限

    则0755表示用户具有读/写/执行权限,组用户和其它用户具有读写权限;0644表示用户具有读写权限,组用户和其他用户具有只读权限

    4. 演示源码

    git地址

  • 相关阅读:
    LQ0009 平方十位数【枚举】
    DTSE Tech Talk丨第2期:1小时深度解读SaaS应用系统设计
    find、Window、Size、
    IDEA基本使用说明,入门必看
    Spring组件注入注意事项之一
    数仓:数仓建设中的数据建模和日志体系
    Java基础-面向对象进阶-static,继承
    STL技巧大赏
    数据库基础和DDL
    3dmax 单位匹配和基本单位设置
  • 原文地址:https://blog.csdn.net/qq_24950043/article/details/126555657