背景
為實作快速搭建和開發,項目以Springboot架構搭建,springboot搭建的項目可以将項目直接打成jar包并運作,無需自己安裝配置Tomcat或者其他伺服器,是一種友善快捷的部署方式。
假設項目以最正常的方式打包成一個整體的jar包部署,即配置檔案和第三方依賴包都包含在jar包裡,就會有如下兩個問題
問題一:項目運作過程中,要改動配置檔案的話需要重新打包并部署。
問題二:多個第三方依賴包都相近的項目要部署在同一台伺服器時,各自的jar包都包含了相同的第三方依賴包(假設項目jar包有100M,第三方依賴包可能就占用了99M),這樣第三方依賴包備援造成了伺服器資源的浪費以及降低了項目部署的效率。
如果将各項目的配置檔案、第三方依賴包都提取到jar包外統一管理,這樣即提升了項目打包效率又節約了伺服器的磁盤消耗,同時項目的運維也是非常友善的,改動了配置檔案重新開機下服務就可以了,無需重新建構部署。
下面是具體的實作方案
1. 配置檔案統一管理
1.1 springboot核心配置檔案
Springboot讀取核心配置檔案(application.properties)的優先級為
Jar包同級目錄的config目錄
Jar包同級目錄
classPath(即resources目錄)的config目錄
classpath目錄
上面是springboot預設去拿自己的核心配置檔案的優先級,還有一種最高優先級的方式是項目啟動時通過指令的方式指定項目加載核心配置檔案,指令如下
java –jar -Dspring.config.location=xxx/xxx/xxxx.properties xxxx.jar
如果Spring Boot在優先級更高的位置找到了配置,那麼它會無視優先級更低的配置
1.2 其他資源配置檔案
上面描述的Springboot核心檔案已經能夠提取出jar包外進行管理了,但是還有其他一些業務上的配置檔案,如資料源配置檔案,公共資源定義配置檔案(常量,FTP資訊等),quartz定時器,日志等配置檔案我們如何去提取出來并確定能在代碼中引用到呢
我們知道Springboot項目可以通過注解方式來擷取相關配置檔案,是以我們也是通過注解方式讓項目能夠引用到jar包外部的配置檔案的,如下圖:

@PropertySource裡面的value有兩個值,第一個是classpath下config目錄下的資料源配置檔案,第二個則是根據spring.profiles.path動态擷取的目錄,spring.profiles.path是我們在核心檔案自定義的一個配置項,它的值是我們配置檔案統一管理的檔案夾路徑,後面的ignoreResourceNotFound=true則是設定假如根據前面一個路徑沒有找到相關配置檔案,則根據第二個路徑去找。
我們還可以直接根據路徑,用FileSystemResource類去加載一個配置檔案執行個體出來,如下圖
原理類似,根據在核心檔案自定義的統一配置目錄的路徑來加載配置檔案
另外logback日志配置檔案加載方式如下:
綜上所述,我們梳理一下實作方案的思路
1、 在springboot核心檔案裡定義一個spring.profiles.path配置項,它的值指向我們所有配置檔案統一放置的目錄,包含核心檔案自身也是放置在裡面的
2、 代碼或者配置檔案裡加載配置檔案的地方也應該擷取spring.profiles.path配置項來動态加載該路徑下的配置檔案
3、 Pom.xml檔案修改打包相關子產品,将配置檔案排除,這樣我們打出的jar包是不含配置檔案的,打包配置請參考文檔節點3
4、 啟動jar包時,通過指令指定加載的核心檔案為spring.profiles.path下的核心檔案
2. 第三方依賴包統一管理
通常第三方jar包可以打進jar包裡,也可以放在項目jar包同級目錄下的lib目錄,我們可以根據修改pom.xml打包配置來實作,請參考文檔節點3打包配置
3. 打包配置
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<!—打包時排除配置檔案-->
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
<exclude>**/*.yml</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<fork>true</fork>
<skip>true</skip>
<executable>
C:/Program Files/Java/jdk1.8.0_161/bin/javac.exe
</executable>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<useUniqueVersions>false</useUniqueVersions>
<mainClass>com.xrq.demo.Application</mainClass>
</manifest>
<manifestEntries>
<Class-Path>./</Class-Path>
</manifestEntries>
</archive>
<excludes>
<exclude>*.properties</exclude>
<exclude>*.yml</exclude>
<exclude>*.xml</exclude>
<exclude>config/**</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
改好pom.xml的build子產品後,就可以通過mvn package 或者mvn install打出我們的jar包了
4. 項目管理 shell 腳本編寫
自定義shell腳本,實作項目的啟動,停止,狀态,重新開機操作:
#!/bin/bash
#這裡可替換為你自己的執行程式,其他代碼無需更改
APP_NAME=demo1-0.0.1-SNAPSHOT.jar
JVM="-server -Xms512m -Xmx512m -XX:PermSize=64M -XX:MaxNewSize=128m -XX:MaxPermSize=128m -Djava.awt.headless=true -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled"
APPFILE_PATH="-Dspring.config.location=/usr/local/demo/config/application-demo1.properties"
#使用說明,用來提示輸入參數
usage() {
echo "Usage: sh 執行腳本.sh [start|stop|restart|status]"
exit 1
}
#檢查程式是否在運作
is_exist(){
pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
#如果不存在傳回1,存在傳回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
#啟動方法
start(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is already running. pid=${pid} ."
else
nohup java $JVM -jar $APPFILE_PATH $APP_NAME > /dev/null 2>&1
fi
}
#停止方法
stop(){
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
else
echo "${APP_NAME} is not running"
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
5. 部署
linux伺服器上建立個檔案夾,将我們打好的項目jar包都丢進去,在jar包的同級目錄建立config和lib檔案夾,分别将配置檔案和第三方依賴包丢進去,其結構如下圖,*.sh為自己寫的項目啟動shell腳本
打開config内的springboot核心檔案(如application-demo1.properties檔案),
spring.profiles.path配置項改成目前配置檔案所在的目錄,假設為/usr/local/demo/config
打開*.sh腳本,修改APPFILE_PATH的值,如下
APPFILE_PATH="-Dspring.config.location=/usr/local/demo/config/application-demo1.properties"
6. 項目管理
進入jar包所在目錄執行下面指令
sh demo1.sh start 啟動項目
sh demo1.sh stop 停止項目
sh demo1.sh restart重新開機項目
sh demo1.sh status項目狀态