公司的這種打包啟動方式,我簡直驚呆了

語言: CN / TW / HK

theme: cyanosis

前言

大家都知道,SpringBoot應用最終會打出一個Fat Jar, 裡面包含了用到的全部依賴,啟動也非常簡單,java -jar xxx.jar即可。

但是我們公司打出的最終包,將依賴包挪到了外部,然後啟動的時候通過loader.path指定依賴包的位置,如java -Dloader.path=libs -jar xxxx的方式啟動,也能夠啟動成功。

這樣做最大的一個好處就是如果發現某個依賴出現問題,那麼我只需要在libs替換其中某個依賴,影響範圍可以減小很多。

那大家是不是很好奇是怎麼做到的呢?

打包方式詳解

主要是通過兩個maven外掛打出這樣的結構的包。

  1. spring-boot-maven-plugin

該外掛是spring boot官方提供的一個打包外掛,主要用來打出fat jar,並且提供了支援java -jar xxx.jar方式啟動。 官網地址:https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/htmlsingle/

我們需要用這個外掛,因為只有它可以打出支援啟動的jar,但是打出的包中又不能有依賴,該怎麼做呢?如下圖:

  • layout: 佈局方式,這裡要選擇ZIP,後面說明原因。
  • includes: 選擇包含哪些依賴,這裡寫了一個不存在的jar,那麼也間接實現了不打入其他的依賴。這種方式比較ugly,但是目前沒有找到更加合適的方案。

  • maven-assembly-plugin

maven-assembly-plugin外掛可以靈活定製打包內容,官網地址:https://maven.apache.org/plugins/maven-assembly-plugin/

我們現在就是想辦法利用該外掛抽出我們用到的依賴包,該怎麼做呢?

我們現在看下assembly.xml中的關鍵配置:

  • 可以根據includeexclude屬性通過正則靈活的抽取相關依賴到指定的目錄下

最終執行mvn clean package在target目錄下得到最終的安裝包:

解壓該安裝包:

開啟libs目錄:

啟動方式解析

現在我們已經按照自己想要的結構打出包了,那如何在啟動的時候載入libs目錄中的依賴呢?

前面提到了springboot外掛打出的包是啟動的入口,實際上在這個包裡面springboot會自動打入一個引導類org.springframework.boot.loader.Launcher,它是 Spring Boot 可執行 jar 的主要入口點,它是 Spring Boot jar 檔案中的實際 Main-Class,用於設定適當的 URLClassLoader 並最終呼叫Spring Boot專案中定義的 main()方法。

Launcher有三個子類(JarLauncherWarLauncherPropertiesLauncher),如果我們打包外掛的layout配置的是ZIP的方式,它會使用PropertiesLauncher

PropertiesLauncher機制說明:

預設情況下,PropertiesLauncherBOOT-INF/lib/ 中載入,我們可以通過設定loader.properties中的loader.pathLOADER_PATH 環境變數來增加其它的載入位置。

  • loader.path:配置逗號分隔的 Classpath 類路徑,例如 lib,${HOME}/app/lib,前面的路徑優先,類似於 javac 命令中的 -classpath
  • loader.home:用於解析 loader.path 配置的相對路徑,預設是${user.dir}

所以,打包成功後,我們可以通過java -jar -Dloader.path=xx1,xx2,public <jarName>.jar 命令來啟動程式,這樣對應目錄下的依賴均會被載入。

總結

這種打包啟動方式雖然不常見,但是還是有一定的價值的,特別是在專案元件模組比較多的時候,出現緊急缺陷,可以按需替換包,將影響範圍控制到最小。

如果本文對你有幫助,請隨手留下一個贊吧。

本文正在參加「金石計劃 . 瓜分6萬現金大獎」