Spring Boot使用maven-assembly打包和部署

4,522 阅读2分钟

介绍

我们使用spring-boot-maven-plugin打包,会生成一个整体的jar包(Fatjar),配置文件和模块jar包都打进去了。如果想手动修改配置或者替换部分jar的话是实现不了的。

assembly可以加载jar外的配置文件,可以很好的解决上面的问题。另外我们可以编写应用服务脚本(启动,关闭等),配置到相关的自定义文件(通常是bin)下,这样就可以很方便的对springboot项目进行操作。

我们会设置在jar包同等级的目录下创建一个config目录,config目录下在再放一份application.properties,这样做是为了便于从外部修改配置。这是因为springboot读取配置的优先级决定的。优先级如下:

1.jar包同级目录的config目录下的配置

2.当前目录下配置

3.classpath的config目录下配置

4.classpath根目录配置

assembly配置

配置内容如下:

pom.xml配置

我们先来配置下项目的pom.xml,如下所示:

<build>
    <finalName>manage-web</finalName>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <excludes>
                <exclude>*.properties</exclude>
            </excludes>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
            <includes>
                <include>application.properties</include>
                <include>application-${profile.env}.properties</include>
            </includes>
        </resource>
    </resources>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <classesDirectory>target/classes/</classesDirectory>
                <archive>
                    <!--生成的jar包不包含maven描述相关文件-->
                    <addMavenDescriptor>false</addMavenDescriptor>
                    <manifest>
                        <!--项目启动类-->
                        <mainClass>com.wk.manage.web.WebApplication</mainClass>
                        <useUniqueVersions>false</useUniqueVersions>
                        <!--第三方JAR加入类构建的路径maven-dependency-plugin-->
                        <addClasspath>true</addClasspath>
                        <!--外部依赖jar包的位置-->
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                    <manifestEntries>
                        <Class-Path>.</Class-Path>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>

        <!--关键插件,maven提供的assembly插件,需要放在最后-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <id>make-tar.gz</id>
                    <!--绑定的maven操作-->
                    <phase>package</phase>
                    <!--运行一次-->
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                    
                        <!--如果不想在打包的后缀加上assembly.xml中设置的id,可以加上下面的配置-->
                        <!--<appendAssemblyId>false</appendAssemblyId>-->

                        <!--指定assembly插件对应的assembly.xml配置文件-->
                        <descriptors>
                            <descriptor>src/main/resources/assembly/assembly.xml</descriptor>
                        </descriptors>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

assembly.xml配置

然后我们需要在pom文件中指定的assembly插件对应的assembly.xml配置文件进行配置:

<assembly
        xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <!--必填,会追加到打包文件名称的末尾-->
    <id>1.0</id>
    <!--打包类型,可以设置多种类型,打包的时候不同的类型都会打包打出来-->
    <formats>
        <format>tar.gz</format>
        <!--<format>zip</format>-->
    </formats>
    <!--第三方依赖设置-->
    <dependencySets>
        <dependencySet>
            <!--使用项目中的artifact,第三方包打包进tar.gz文件的lib目录下-->
            <useProjectArtifact>true</useProjectArtifact>
            <outputDirectory>lib</outputDirectory>
        </dependencySet>
    </dependencySets>

    <!--文件相关设置-->
    <fileSets>
        <!--src/main/assembly/bin文件下的所有脚本文件输出到打包后的bin目录下-->
        <fileSet>
            <directory>src/main/resources/assembly/bin</directory>
            <outputDirectory>bin</outputDirectory>
            <!--
            权限设置:
             0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限;
               0644->即用户具有读写权限,组用户和其它用户具有只读权限;
            -->
            <fileMode>0755</fileMode>
            <lineEnding>unix</lineEnding>
            <filtered>true</filtered>
        </fileSet>

        <!-- src/main/resources/config目录下配置文件打包到config目录下 -->
        <fileSet>
            <directory>src/main/resources</directory>
            <includes>
                <include>application.properties</include>
                <include>application-${profile.env}.properties</include>
            </includes>
            <filtered>true</filtered>
            <outputDirectory>${file.separator}config</outputDirectory>
        </fileSet>

        <!-- 将target目录下的启动jar打包到目录下-->
        <fileSet>
            <directory>target</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

服务脚本配置

接下来配置下启动、关闭、重启以及查询状态的脚本,由assembly.xml可以看出放置的位置为src/main/resources/assembly/bin(可自定义):

#!/bin/sh

## service name(TODO-需要替换为自己服务名称)
APP_NAME=manage-web
## 启动等待最长时间
MAX_START_WAIT_SEC=60
## 当前等待时间
WAIT_SEC=1


## 服务所在路径(TODO-需要替换为自己的路径)
SERVICE_DIR=/Users/wukong/Desktop/tool/$APP_NAME
APP_DIR=$HOME
JAVA_JDK=jdk1.8.0_144
SERVICE_NAME=$APP_NAME
JAR_NAME=$SERVICE_NAME.jar
PID=$SERVICE_NAME.pid
PID_BAK=$PID.bak
## heap dump路径(TODO-需要替换为自己的路径)
HEAP_DUMP_PATH=/Users/wukong/Desktop/tool/logs/$APP_NAME/

cd $SERVICE_DIR

#使用说明,用来提示输入参数
usage() {
echo "Usage: sh 脚本名.sh [start|stop|restart|status]"
exit 1
}

#启动方法
start(){
nohup java -Djava.security.egd=file:/dev/./urandom -server -Xms1024m -Xmx1024m -Xmn512m -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection -Xloggc:gc.log -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HEAP_DUMP_PATH -jar $JAR_NAME >/dev/null 2>&1 &
        echo $! > $SERVICE_DIR/$PID
        echo "================================================== start $SERVICE_NAME begin... please wait $MAX_START_WAIT_SEC sec"
        while((WAIT_SEC < MAX_START_WAIT_SEC))
        do
     P_ID=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | awk '{print $2}'`
            P_ID_COUNT=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | wc -l`
            if [ $P_ID_COUNT = 0 ];then
                echo "================================================== start $SERVICE_NAME begin... wait time :$WAIT_SEC / $MAX_START_WAIT_SEC | P_ID_COUNT=$P_ID_COUNT"
  sleep 1
            else
                echo "================================================== start $SERVICE_NAME succeeded. pid=$P_ID,  costTime:$WAIT_SEC"
                let "WAIT_SEC = MAX_START_WAIT_SEC"
            fi
            let "WAIT_SEC += 1"
        done
}

#停止方法
stop(){
is_exist
if [ $? -eq "0" ]; then
echo "=== stop $SERVICE_NAME begin... please wait $MAX_START_WAIT_SEC sec"
        kill -15 `cat $SERVICE_DIR/$PID`
        mv $SERVICE_DIR/$PID $SERVICE_DIR/$PID_BAK
        rm -rf $SERVICE_DIR/$PID

  while((WAIT_SEC < MAX_START_WAIT_SEC))
        do
   P_ID=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | awk '{print $2}'`
            P_ID_COUNT=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | wc -l`
            if [ $P_ID_COUNT != 0 ]; then
                echo "=== stop $SERVICE_NAME begin by (kill -15)... wait time :$WAIT_SEC / $MAX_START_WAIT_SEC | P_ID_COUNT=$P_ID_COUNT"
    sleep 1
            else
                echo "=== stop $SERVICE_NAME succeeded by (kill -15). costTime:$WAIT_SEC"
                let "WAIT_SEC = MAX_START_WAIT_SEC"
            fi
            let "WAIT_SEC += 1"
        done

  P_ID=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | awk '{print $2}'`
        P_ID_COUNT=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | wc -l`
  if [ $P_ID_COUNT != 0 ];then
   echo "=== stop $SERVICE_NAME begin by (kill -15) failed. begin kill -9 $SERVICE_NAME process, pid is:$P_ID"
            kill -9 $P_ID
            echo "${APP_NAME} is not running"
  fi
else
echo "${APP_NAME} is not running"
fi
}


#检查程序是否在运行
is_exist(){
pid=`ps -ef | grep -w "$JAR_NAME" | grep -w "java" | grep -v "grep" | awk '{print $2}'`
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}

#输出运行状态
status(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is running. Pid is ${pid}"
else
echo "${APP_NAME} is NOT running."
fi
}

#重启
restart(){
stop
start
}


#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac

项目打包

以上配置好以后,在idea中执行clean package对项目进行打包。打包名称为manage-web-1.0.tar.gz(1.0为assembly.xml中设置的id)。我们对包进行解压看下里面的目录结构。

image.png

我们可以看到和assembly.xml配置的结构是一致的。我们启动项目只要执行bin目录下的脚本即可。如果想覆盖图中manage-web.jar中的application.properties相关配置,可以在config中的配置进行设置。