使用Assembly打包和部署SpringBoot工程方式
1、Spring Boot項目的2種部署方式
目前來說,Spring Boot 項目有如下 2 種常見的部署方式。
1、一種是使用 docker 容器去部署。將 Spring Boot 的應用構建成一個 docker image,然后通過容器去啟動鏡像。這種方式在需要部署大規(guī)模的應用以及對應用進行擴展時,是非常方便的,屬于目前工業(yè)級的部署方案,但是需要掌握 docker 的生態(tài)圈技術。
2、另一種則是使用 FatJar 直接部署啟動(將一個 jar 及其依賴的三方 jar 全部打到一個包中,這個包即為 FatJar)。這是很多初學者或者極小規(guī)模情況下的一個簡單應用部署方式。
2、Assembly 的優(yōu)勢
上面介紹的 Fatjar 部署方案存在以下缺陷。
1、如果直接構建一個 Spring Boot 的 FatJar 交由運維人員部署的話,整個配置文件都被隱藏到 jar 中,想要針對不同的環(huán)境修改配置文件就變成了一件很困難的事情。
2、如果需要啟動腳本啟動項目的時候,這種直接通過 jar 的方式后續(xù)會需要處理很多工作。
而通過 assembly 將 Spring Boot 服務化打包,便能解決上面提到的 2 個問題。
1、使得 Spring Boot 能夠加載 jar 外的配置文件。
2、提供一個服務化的啟動腳本,這個腳本一般是 shell 或者 windows 下的 bat ,有了 Spring Boot 的應用服務腳本后,就可以很容易的去啟動和停止 Spring Boot 的應用了。
3、項目配置
3.1、添加插件
編輯項目的 pom.xml 文件,加入 assembly 打包插件。
<build>
<!-- 指定需要打包編譯的文件 -->
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<plugins>
<!-- 指定啟動類,將依賴打成外部jar包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<!-- 不打包配置文件 -->
<excludes>
<exclude>*.xml</exclude>
<exclude>*.properties</exclude>
<exclude>*.yml</exclude>
</excludes>
<archive>
<!-- 生成的jar中,不要包含pom.xml和pom.properties這兩個文件 -->
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<!-- 是否要把第三方jar加入到類構建路徑 -->
<addClasspath>true</addClasspath>
<!-- 外部依賴jar包的最終位置 -->
<classpathPrefix>../lib</classpathPrefix>
<!-- 項目啟動類 -->
<mainClass>com.example.TestApplication</mainClass>
</manifest>
<manifestEntries>
<!--MANIFEST.MF 中 Class-Path 加入配置文件目錄-->
<Class-Path>../config/</Class-Path>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
</configuration>
</plugin>
<!-- 拷貝配置文件到config目錄下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*.xml</include>
<include>*.properties</include>
<include>*.yml</include>
</includes>
</resource>
</resources>
<outputDirectory>${project.build.directory}/config</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- 將依賴jar包拷貝到lib目錄下 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- 打包插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<finalName>${project.artifactId}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<!--具體的配置文件-->
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!--綁定到maven操作類型上-->
<phase>package</phase>
<!--運行一次-->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 打包時跳過測試 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>從上面代碼可以看出,把 assembly 的配置都放在 main/assembly 目錄下(具體目錄里面的文件接下來會創(chuàng)建)。

3.2、編寫服務啟動/停止/重啟腳本
在 assembly 目錄下創(chuàng)建一個 bin 文件夾,然后在該文件夾下創(chuàng)建 start.sh 文件,這個是 linux 環(huán)境下的啟動腳本,具體內容如下。
Tip:開頭的項目名稱、jar 包名稱不用我們手動設置,這里使用參數(shù)變量,在項目打包后這些參數(shù)自動會替換為 pom 的 profiles 中 properties 的值(assembly 配置文件需要開啟屬性替換功能),下面另外兩個配置文件也同理。
#!/bin/bash
# 項目名稱
SERVER_NAME="${project.artifactId}"
# jar名稱
APPLICATION="${project.build.finalName}"
# 進入bin目錄
cd `dirname $0`
# bin目錄絕對路徑
BIN_PATH=`pwd`
# 返回到上一級項目根目錄路徑
cd ..
# 打印項目根目錄絕對路徑
# `pwd` 執(zhí)行系統(tǒng)命令并獲得結果
BASE_PATH=`pwd`
# 外部配置文件絕對目錄,如果是目錄需要/結尾,也可以直接指定文件
# 如果指定的是目錄,spring則會讀取目錄中的所有配置文件
CONFIG_PATH=$BASE_PATH/config
LOG_PATH=$BASE_PATH/logs/${SERVER_NAME}
JAVA_OPT="-server -Xms1024m -Xmx1024m -Xmn512m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
APPLICATION_JAR=$(ls $BASE_PATH/boot/$APPLICATION.jar)
PROCESS_ID=$(ps -ef|grep $BASE_PATH/boot/$APPLICATION|grep -v grep|awk '{print $2}')
if [ ! -n "$PROCESS_ID" ];then
echo "$SERVER_NAME服務,進程正在啟動中,請稍等..."
file="nohup.out"
if [ ! -f "$file" ]; then
touch "$file"
fi
source /etc/profile
nohup java ${JAVA_OPT} -jar ${APPLICATION_JAR} > /dev/null &
tail -f "${LOG_PATH}/system/info.log"
else
echo "$SERVER_NAME服務,進程(id:$PROCESS_ID)已存在,啟動失敗"
fi創(chuàng)建 stop.sh 文件,這個是 linux 環(huán)境下的停止腳本,具體內容如下。
#!/bin/bash
# 項目名稱
APPLICATION="${project.artifactId}"
# 項目啟動jar包名稱
APPLICATION_JAR="${project.build.finalName}.jar"
# 通過項目名稱查找到PID,然后kill -9 pid
PROCESS_ID=$(ps -ef|grep "${APPLICATION_JAR}" |grep -v grep|awk '{print $2}')
if [[ -z "$PROCESS_ID" ]]
then
echo "$APPLICATION服務沒有啟動,請進一步驗證是否需要停止進程"
else
echo "$APPLICATION服務,進程已存在,正在kill進程,進程ID:$PROCESS_ID"
kill -9 ${PROCESS_ID}
echo "$APPLICATION服務,進程$PROCESS_ID停止成功"
fi創(chuàng)建 restart.sh 文件,這個是 linux 環(huán)境下的重啟腳本,具體內容如下。
#!/bin/bash
# 項目名稱
APPLICATION="${project.artifactId}"
# 進入bin目錄
cd `dirname $0`
# bin目錄絕對路徑
BIN_PATH=`pwd`
echo "$APPLICATION服務正在停止"
sh $BIN_PATH/stop.sh
echo "$APPLICATION服務正在重啟"
sh $BIN_PATH/start.sh創(chuàng)建 server.sh 文件,這個是 linux 環(huán)境下根據(jù)指令執(zhí)行服務啟動、停止、重啟、查看狀態(tài)的腳本,具體內容如下。
#!/bin/bash
# 項目名稱
SERVER_NAME="${project.artifactId}"
# jar名稱
APPLICATION=${project.build.finalName}
# 進入bin目錄
cd `dirname $0`
# bin目錄絕對路徑
BIN_PATH=`pwd`
# 返回到上一級項目根目錄路徑
cd ..
# 打印項目根目錄絕對路徑
# `pwd` 執(zhí)行系統(tǒng)命令并獲得結果
BASE_PATH=`pwd`
# 外部配置文件絕對目錄,如果是目錄需要/結尾,也可以直接指定文件
CONFIG_PATH=$BASE_PATH/config
APP_NAME=$BASE_PATH/boot/$APPLICATION.jar
LOG_PATH=$BASE_PATH/logs/${SERVER_NAME}
JAVA_OPT="-server -Xms512m -Xmx1024m -Xmn512m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
#判斷用戶是否為lbs
loginUser() {
USER=`whoami`
if [ ${USER} != "lbs" ];then
echo "Please use user 'lbs'"
exit 1
fi
}
loginUser
# 使用說明,用來提示輸入?yún)?shù)
usage() {
echo "Usage: sh server.sh [start|stop|restart|status]"
exit 1
}
# 檢查程序是否在運行
is_exist() {
# 根據(jù)關鍵字過濾進程PID,關鍵字由業(yè)務方自定義
pid=$(ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}')
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
# 啟動程序
start() {
# 啟動程序時,可酌情根據(jù)各自服務啟動條件做出相應的調整
is_exist
if [ $? -eq "0" ]; then
echo "${SERVER_NAME}服務進程已存在,pid=${pid}"
else
if [ ! -f "$LOG_PATH" ]; then
touch "$LOG_PATH"
fi
source /etc/profile
nohup java $JAVA_OPT -jar $APP_NAME >$LOG_PATH 2>&1 &
# 應以非阻塞方式執(zhí)行服務啟動命令,避免腳本一直阻塞在這里無法退出
# 業(yè)務方應對其服務啟動時間進行預估,如果從 命令下發(fā)到端口開啟并對外提供服務 期間的時長超過了1分鐘
# 那么業(yè)務方則需酌情在此處使用sleep來阻塞腳本,避免因啟動時間過長導致持續(xù)交付系統(tǒng)誤判
# 這個阻塞的時間按照各業(yè)務方不同服務自行設定
# 且執(zhí)行啟動命令后,相關的服務日志應存儲到指定的文件
echo "${SERVER_NAME}服務進程啟動成功"
fi
}
# 停止程序
stop() {
# 服務停止方式及具體方法由業(yè)務方指定,避免因直接kill掉進程而影響線上業(yè)務
# 并且確保stop函數(shù)執(zhí)行結束后,服務進程不存在,避免影響后續(xù)操作
is_exist
if [ $? -eq "0" ]; then
# 如果服務需要平穩(wěn)的停止,保證業(yè)務流無問題,那么可使用不限于循環(huán)等方式,保證stop執(zhí)行后已經(jīng)停止了該服務
# 否則后續(xù)操作可能會影響相關的業(yè)務,務必確保stop函數(shù)執(zhí)行結果的準確性
kill -9 $pid
echo "${SERVER_NAME}服務進程停止成功,pid=$pid"
else
echo "${SERVER_NAME}服務沒有啟動,請進一步驗證是否需要停止進程"
fi
}
# 程序狀態(tài)
status() {
is_exist
if [ $? -eq "0" ]; then
echo "${SERVER_NAME}服務進程正在運行,pid=${pid}"
else
echo "${SERVER_NAME}服務進程沒有啟動"
fi
}
# 重啟程序
restart() {
stop
start
}
# 主方法入口,接收參數(shù)可支持start\stop\status\restart\
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac創(chuàng)建 start.bat 文件,這個是 Windows 環(huán)境下的啟動腳本,具體內容如下。
echo off
:: 項目名稱
set APP_NAME=${project.artifactId}
:: jar名稱
set APP_JAR=${project.build.finalName}.jar
echo "開始啟動服務 %APP_NAME%"
java -Xms512m -Xmx512m -server -jar ../boot/%APP_JAR%
echo "java -Xms512m -Xmx512m -server -jar ../boot/%APP_JAR%"
goto end
:end
pause3.3、創(chuàng)建打包配置文件
最后,我們在 assembly 文件夾下創(chuàng)建一個 assembly.xml 配置文件,具體內容如下。
<assembly>
<!--
必須寫,否則打包時會有 assembly ID must be present and non-empty 錯誤
這個名字最終會追加到打包的名字的末尾,如項目的名字為 test-0.0.1-SNAPSHOT,
則最終生成的包名為 test-0.0.1-SNAPSHOT-assembly.tar.gz
-->
<id>assembly</id>
<!-- 打包的類型,如果有N個,將會打N個類型的包 -->
<formats>
<format>tar.gz</format>
<!--<format>zip</format>-->
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<!--第三方依賴設置-->
<dependencySets>
<dependencySet>
<!-- 不使用項目的artifact,第三方jar不要解壓,打包進zip文件的lib目錄 -->
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
<!--文件設置-->
<fileSets>
<!--
0755->即用戶具有讀/寫/執(zhí)行權限,組用戶和其它用戶具有讀寫權限;
0644->即用戶具有讀寫權限,組用戶和其它用戶具有只讀權限;
-->
<!-- 將src/main/assembly/bin目錄下的所有文件輸出到打包后的bin目錄中 -->
<fileSet>
<directory>${basedir}/src/main/assembly/bin</directory>
<outputDirectory>bin</outputDirectory>
<fileMode>0755</fileMode>
<!--如果是腳本,一定要改為unix.如果是在windows上面編碼,會出現(xiàn)dos編寫問題-->
<lineEnding>unix</lineEnding>
<filtered>true</filtered><!-- 是否進行屬性替換 -->
</fileSet>
<!-- 將src/main/resources下配置文件打包到config目錄 -->
<fileSet>
<directory>${basedir}/src/main/resources</directory>
<outputDirectory>/config</outputDirectory>
<includes>
<include>*.xml</include>
<include>*.properties</include>
<include>*.yml</include>
</includes>
<filtered>true</filtered><!-- 是否進行屬性替換 -->
</fileSet>
<!-- 將第三方依賴打包到lib目錄中 -->
<fileSet>
<directory>${basedir}/target/lib</directory>
<outputDirectory>lib</outputDirectory>
<fileMode>0755</fileMode>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
<!-- 將項目啟動jar打包到boot目錄中 -->
<fileSet>
<directory>${basedir}/target</directory>
<outputDirectory>boot</outputDirectory>
<includes>
<include>${project.build.finalName}.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>3.4、打包測試
配置修改完畢后,我們對項目進行打包。將生成的壓縮包解壓后可以發(fā)現(xiàn),boot 文件夾下項目 jar 包和lib文件夾下第三方 jar 分開了,并且項目 jar 體積也十分小巧。

總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
前端dist包放到后端springboot項目下一起打包圖文教程
這篇文章主要介紹了前端dist包放到后端springboot項目下一起打包的相關資料,具體步驟包括前端打包、將前端文件復制到后端項目的static目錄、后端打包、驗證部署成功等,需要的朋友可以參考下2025-01-01
spring6+JDK17實現(xiàn)SSM起步配置文件
本文介紹了使用Spring6和JDK17配置SSM(Spring + Spring MVC + MyBatis)框架,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-01-01
IDEA運行spring項目時,控制臺未出現(xiàn)的解決方案
文章總結了在使用IDEA運行代碼時,控制臺未出現(xiàn)的問題和解決方案,問題可能是由于點擊圖標或重啟IDEA后控制臺仍未顯示,解決方案提供了解決方法,包括通過右三角Run運行(快捷鍵:Alt+42)或以Debug運行(快捷鍵:Alt+5)來解決2025-01-01
Java Thread多線程開發(fā)中Object類詳細講解
這篇文章主要介紹了Java Thread多線程開發(fā)中Object類,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2023-03-03

