springboot- 使用assembly進行項目打包


一、基本介紹

1、部署方式介紹

目前來說,SpringBoot 項目有如下兩種常見的部署方式:一種是使用 docker 容器去部署。將 Spring Boot 的應用構建成一個 docker image,然后通過容器去啟動鏡像,這種方式在需要部署大規模的應用、以及應用擴展時是非常方便的,屬於目前工業級的部署方案,但是需要掌握 docker 的生態圈技術。 另一種則是使用 FatJar 直接部署啟動(將一個 jar 及其依賴的三方 jar 全部打到一個包中,這個包即為 FatJar),這是很多初學者或者極小規模情況下的一個簡單應用部署方式。

2、使用 assembly 的優勢

(1)上面介紹的 Fatjar 部署方案存在一些缺陷。因為我們如果直接構建一個 Spring Boot 的 FatJar 交由運維人員部署的話,整個配置文件都被隱藏到 jar 中,想要針對不同的環境修改配置文件就變成了一件很困難的事情。如果存在環境不確定,或者需要啟動腳本啟動項目的時候,這種直接通過 jar 的方式后續會需要處理很多工作。

(2)而通過 assembly 將 Spring Boot 服務化打包,便能解決上面提到的兩個問題:

  • 使得 Spring Boot 能夠加載 jar 外的配置文件。
  • 提供一個服務化的啟動腳本,這個腳本一般是 shell 或者 windows 下的 bat ,有了 Spring Boot 的應用服務腳本后,就可以很容易的去啟動和停止 Spring Boot 的應用了。

二、項目配置

1、添加插件
1)編輯項目的 pom.xml 文件,加入 assembly 打包插件:

<plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <id>maven-assembly</id>
                        <!--綁定到maven操作類型上-->
                        <phase>package</phase>
                        <!--運行一次-->
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <!-- zip包文件名 -->
                            <finalName>${project.artifactId}</finalName>
                            <!-- zip包文件名不加上assembly.xml中配置的id屬性值 -->
                            <appendAssemblyId>false</appendAssemblyId>
                            <descriptors>
                                <!--具體的配置文件-->
                                <descriptor>src/main/assembly/assembly.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

2)從上面代碼可以看出,我把 assembly 的配置放在 main/assembly 目錄下。大家可以根據習慣使用其他目錄,只要對上面配置做相應修改即可。

 

 

 3)編寫assembly文件

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation
="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> <id>bin</id> <!-- 打包的類型,如果有N個,將會打N個類型的包 --> <formats> <!--<format>tar.gz</format>--> <format>zip</format> </formats> <!--是否包裝一層--> <includeBaseDirectory>true</includeBaseDirectory> <!--文件設置--> <fileSets> <!-- 0755->即用戶具有讀/寫/執行權限,組用戶和其它用戶具有讀寫權限; 0644->即用戶具有讀寫權限,組用戶和其它用戶具有只讀權限; --> <!-- 將src/main/bin目錄下的所有文件輸出到打包后的bin目錄中 --> <fileSet> <directory>src/main/bin</directory> <outputDirectory>bin</outputDirectory> <fileMode>0755</fileMode> <!--如果是腳本,一定要改為unix.如果是在windows上面編碼,會出現dos編寫問題--> <lineEnding>unix</lineEnding> <filtered>true</filtered><!-- 是否進行屬性替換 --> </fileSet> <!-- 將src/main/assembly/config目錄下的所有文件輸出到打包后的config目錄中 --> <!--<fileSet> <directory>src/main/assembly/config</directory> <outputDirectory>config</outputDirectory> <fileMode>0644</fileMode> </fileSet>--> <!-- 將src/main/resources下配置文件打包到config目錄 --> <fileSet> <directory>src/main/resources</directory> <outputDirectory>config</outputDirectory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> <include>**/*.yml</include> </includes> <filtered>true</filtered><!-- 是否進行屬性替換 --> </fileSet> <!-- 將項目啟動jar打包到lib目錄中 --> <fileSet> <directory>target</directory> <outputDirectory>lib</outputDirectory> <includes> <include>*.jar</include> </includes> </fileSet> <!-- 將項目說明文檔打包到docs目錄中 --> <!--<fileSet> <directory>.</directory> <outputDirectory>docs</outputDirectory> <includes> <include>*.md</include> </includes> <fileMode>0644</fileMode> </fileSet> <fileSet> <directory>docs</directory> <outputDirectory>docs</outputDirectory> <fileMode>0644</fileMode> </fileSet> <fileSet> <directory>src/main/assembly/docs</directory> <outputDirectory>docs</outputDirectory> <fileMode>0644</fileMode> </fileSet>--> </fileSets> </assembly>

到這一步,執行maven package打包后效果如下:

但是bin文件夾下是空的,因為shell命令的批處理文件還沒寫,下面我們編寫腳本;編寫完成后重新打包即可

2、編寫服務“啟動/停止”腳本
1)首先在 main 目錄下創建一個 bin 文件夾,然后在該文件夾下創建一個 start.sh 文件,這個是 linux 環境下的啟動腳本,具體內容如下:

     注意:開頭的項目名稱、jar 包名稱不用我們手動設置,這里使用參數變量,在項目打包后這些參數自動會替換為 pom 的 profiles 中 properties 的值(assembly 配置文件需要開啟屬性替換功能),下面另外兩個配置文件也同理。

#!/bin/bash

# 項目名稱
SERVER_NAME="${project.artifactId}"
echo "The $SERVER_NAME :  "
# jar名稱
JAR_NAME="${project.build.finalName}.jar"
echo "The $JAR_NAME :  "

# 進入bin目錄
cd `dirname $0`
# bin目錄絕對路徑
BIN_DIR=`pwd`
# 返回到上一級項目根目錄路徑
cd ..
# 打印項目根目錄絕對路徑
# `pwd` 執行系統命令並獲得結果
DEPLOY_DIR=`pwd`

# 外部配置文件絕對目錄,如果是目錄需要/結尾,也可以直接指定文件
# 如果指定的是目錄,spring則會讀取目錄中的所有配置文件
CONF_DIR=$DEPLOY_DIR/config
# SERVER_PORT=`sed '/server.port/!d;s/.*=//' config/application.properties | tr -d '\r'`
# 獲取應用的端口號
SERVER_PORT=`sed -nr '/port: [0-9]+/ s/.*port: +([0-9]+).*/\1/p' config/application.yml`

PIDS=`ps -f | grep java | grep "$CONF_DIR" |awk '{print $2}'`
if [ "$1" = "status" ]; then
    if [ -n "$PIDS" ]; then
        echo "The $SERVER_NAME is running...!"
        echo "PID: $PIDS"
        exit 0
    else
        echo "The $SERVER_NAME is stopped"
        exit 0
    fi
fi

if [ -n "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME already started!"
    echo "PID: $PIDS"
    exit 1
fi

if [ -n "$SERVER_PORT" ]; then
    SERVER_PORT_COUNT=`netstat -tln | grep $SERVER_PORT | wc -l`
    if [ $SERVER_PORT_COUNT -gt 0 ]; then
        echo "ERROR: The $SERVER_NAME port $SERVER_PORT already used!"
        exit 1
    fi
fi

# 項目日志輸出絕對路徑
LOGS_DIR=$DEPLOY_DIR/logs
# 如果logs文件夾不存在,則創建文件夾
if [ ! -d $LOGS_DIR ]; then
    mkdir $LOGS_DIR
fi
STDOUT_FILE=$LOGS_DIR/catalina.log

# JVM Configuration
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
JAVA_DEBUG_OPTS=""
if [ "$1" = "debug" ]; then
    JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n "
fi

JAVA_JMX_OPTS=""
if [ "$1" = "jmx" ]; then
    JAVA_JMX_OPTS=" -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false "
fi

JAVA_MEM_OPTS=""
BITS=`java -version 2>&1 | grep -i 64-bit`
if [ -n "$BITS" ]; then
    JAVA_MEM_OPTS=" -server -Xmx512m -Xms512m -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
else
    JAVA_MEM_OPTS=" -server -Xms512m -Xmx512m -XX:PermSize=128m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi

# 加載外部log4j2文件的配置
LOG_IMPL_FILE=log4j2.xml
LOGGING_CONFIG=""
if [ -f "$CONF_DIR/$LOG_IMPL_FILE" ]
then
    LOGGING_CONFIG="-Dlogging.config=$CONF_DIR/$LOG_IMPL_FILE"
fi
CONFIG_FILES=" -Dlogging.path=$LOGS_DIR $LOGGING_CONFIG -Dspring.config.location=$CONF_DIR/ "
echo -e "Starting the $SERVER_NAME ..."
nohup java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS $CONFIG_FILES -jar $DEPLOY_DIR/lib/$JAR_NAME > $STDOUT_FILE 2>&1 &

COUNT=0
while [ $COUNT -lt 1 ]; do
    echo -e ".\c"
    sleep 1
    if [ -n "$SERVER_PORT" ]; then
        COUNT=`netstat -an | grep $SERVER_PORT | wc -l`
    else
       COUNT=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l`
    fi
    if [ $COUNT -gt 0 ]; then
        break
    fi
done


echo "OK!"
PIDS=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}'`
echo "PID: $PIDS"
echo "STDOUT: $STDOUT_FILE"

2)接着創建一個 stop.sh 文件,這個是 linux 環境下的停止腳本,具體內容如下:

#!/bin/bash

# 項目名稱
APPLICATION="${project.artifactId}"

# 項目啟動jar包名稱
APPLICATION_JAR="${project.build.finalName}.jar"

# 通過項目名稱查找到PI,然后kill -9 pid
PID=$(ps -ef | grep "${APPLICATION_JAR}" | grep -v grep | awk '{ print $2 }')
if [[ -z "$PID" ]]
then
    echo ${APPLICATION} is already stopped
else
    echo kill  ${PID}
    kill -9 ${PID}
    echo ${APPLICATION} stopped successfully
fi

3)最后創建一個 start.bat 文件,這個是 Windows 環境下的啟動腳本,具體內容如下:

echo off
 
set APP_NAME=${project.build.finalName}.jar
set LOG_IMPL_FILE=log4j2.xml
set LOGGING_CONFIG=
if exist ../config/%LOG_IMPL_FILE% (
    set LOGGING_CONFIG=-Dlogging.config=../config/%LOGGING_CONFIG%
)
set CONFIG= -Dlogging.path=../logs %LOGGING_CONFIG% -Dspring.config.location=../config/
 
set DEBUG_OPTS=
if ""%1"" == ""debug"" (
   set DEBUG_OPTS= -Xloggc:../logs/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../logs
   goto debug
)
 
set JMX_OPTS=
if ""%1"" == ""jmx"" (
   set JMX_OPTS= -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9888 -Dcom.sun.management.jmxremote.ssl=FALSE -Dcom.sun.management.jmxremote.authenticate=FALSE
   goto jmx
)
 
echo "Starting the %APP_NAME%"
java -Xms512m -Xmx512m -server %DEBUG_OPTS% %JMX_OPTS% %CONFIG% -jar ../lib/%APP_NAME%
echo "java -Xms512m -Xmx512m -server %DEBUG_OPTS% %JMX_OPTS% %CONFIG% -jar ../lib/%APP_NAME%"
goto end
 
:debug
echo "debug"
java -Xms512m -Xmx512m -server %DEBUG_OPTS% %CONFIG% -jar ../lib/%APP_NAME%
goto end
 
:jmx
java -Xms512m -Xmx512m -server %JMX_OPTS% %CONFIG% -jar ../lib/%APP_NAME%
goto end
 
:end
pause

三、打包測試

1、打包項目
1)我們使用 mvn package 命令對項目進行打包:

 

 2)打包后在 target 下便會生成一個名為 xxx.zip 的壓縮文件:

 

 3)將這個壓縮包解壓后可以看到內部包含的目錄如下:

 

2、啟動服務
1)其中 bin 目錄有如下幾個啟動文件:
   Linux、macOS 系統:執行 start.sh 啟動服務,執行 stop.sh 停止服務。
   Windows 系統:雙擊 start.bat 即可啟動服務

 

 2)服務啟動后,相應的日志文件會生成到 logs 目錄下(logs 目錄會自動創建):

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM