一、問題背景
Spring Boot 項目部署起來雖然已經簡單很多了,但是一個運行 jar 包動輒幾十上百兆,如果服務器是本地或者在內網還好,如果需要在公網環境部署,每次發佈部署時都重新上傳 Spring Boot 的 jar 包,因爲網速的限制,也挺令人頭大的。
二、解構 Spring Boot 的 jar 包
如果我們使用工具打開 Spring Boot 項目編譯出來的 jar 文件,會發現佔用磁盤空間的主要是外部依賴包,位於 jar 包內的 BOOT-INF/lib 路徑下。
大多數情況對服務進行重新部署的時候,外部依賴庫基本上都是不變的,所以這部分的上傳是費時的重複操作。我們可以避免這部分不必要的重複。
三、解決辦法
將外部依賴庫從 Spring Boot 的 jar 包中分離出來,將外部依賴庫單獨上傳服務器,以後每次更新部署的時候只需要上傳瘦身後的 jar 文件,從此上傳就是爽快的秒操作。
- 第一步:修改 Spring Boot 項目的 pom.xml 的插件配置如下,編譯出不包含外部依賴庫的 jar 包:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>
<groupId>nothing</groupId>
<artifactId>nothing</artifactId>
</include>
</includes>
</configuration>
</plugin>
新編譯出 jar 文件後,你會驚喜地發現原來動輒上百兆的文件,瞬間只有幾百 K 的大小。
- 第二步:在項目根目錄下執行如下 mvn 命令,獲得外部依賴包
mvn dependency:copy-dependencies -DoutputDirectory=.\target\lib -Dinclude
=runtime
- 第三步:將外部依賴包和 Spring Boot 服務 jar 包上傳服務器,在 jar 服務啓動命令添加 loader.path 參數指向 外部依賴包的位置路徑:
java -Dloader.path=<外部依賴包位置路徑> -jar spring-boot-demo-0.0.1-SNAPSHOT.jar
當需要再次部署的時候,只需要編譯打包 Spring Boot 服務 jar 包,然後上傳服務器重啓服務就行了,大大提高了效率。
四、一個服務器運行多個 Spring Boot 服務的情況
一般情況下,多個Spring Boot 服務的外部依賴庫很多是重複的,也可以將多個 Spring Boot 服務的外部依賴庫放到同一個目錄位置,在編譯打包 Spring Boot 項目的時候,修改 pom 文件的插件配置如下,使編譯的 jar 文件中產生的 META-INF\MANIFEST.MF 文件中,包含運行時所需要加載的外部依賴庫的信息,然後啓動服務時,會自動按照 jar 文件中的信息加載外部依賴庫:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<!-- 指定項目啓動主類,一般不需要,根據實際情況指定 -->
<!-- <mainClass>${project.main.class}</mainClass> -->
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
上面的示例中,外部依賴庫的 lib 文件夾和可運行的服務的 jar 文件位於同一目錄,這樣運行 jar 文件時,跟根據 MANIFEST.MF 文件的依賴庫路徑信息從當前目錄下的 lib 目錄下加載需要的包文件,此時啓動命令不需要 loader.path 參數。
【完】