【SpringBoot】迭代釋出下的Jar瘦身實踐
背景
隨著Spring Boot
的流行,越來越多開發者選擇使用Spring Boot來發布Web應用。不同於傳統的War包釋出,Spring Boot
把整個專案打包成一個可執行的Jar包(即所謂的Flat Jar),導致了這個Jar包很大(通常有40M+)。如今迭代釋出時常有的事情,每次都上傳一個如此龐大的檔案,會浪費很多時間。
下面就以一個小專案為例,簡述小弟所用的瘦身方案。當然如果是內網釋出或者你用的寬頻異常給力,瘦身就沒有多大意義了。
實踐
專案簡介
新建一個練習用的專案,其結構如下
ht-cdn
存放的是靜態資源(如第三方js、css、images等)ht-domain
專案中的資料實體定義ht-repository
資料層介面及實現ht-service
業務邏輯介面及實現ht-ui-web
Web管理
其中ht-ui-web
依賴於ht-domain
、ht-repository
、ht-service
,實現了一個簡單的GetMapping
。
接著打包專案,整個jar包24M這樣
瘦身準備
首先我們要對Jar包有一個初步認識,它的內部結構如下
example.jar
|
+-META-INF
| +-MANIFEST.MF
+-org
| +-springframework
| +-boot
| +-loader
| +-<spring boot loader classes>
+-BOOT-INF
+-classes
| +-mycompany
| +-project
| +-YourClasses.class
+-lib
+-dependency1.jar
+-dependency2.jar
執行該Jar時預設從BOOT-INF/classes
載入class,從BOOT-INF/lib
載入所依賴的Jar包。如果想要加入外部的依賴Jar,可以通過設定環境變數LOADER_PATH
如此一來,就可以確認我們的思路了:
1. 把那些不變的依賴Jar包(比如spring依賴、資料庫Driver等,這些在不升級版本的情況下是不會更新的)從Flat Jar中抽離到單獨的目錄,如libs
2. 在啟動Jar時,設定LOADER_PATH
使用上一步的libs
這樣,我們最終打包的jar包體積就大大減少,每次迭代後只需要更新這個精簡版的Jar即可。
具體步驟
打包時瘦身
通常我們是用spring-boot-maven-plugin
進行打包,通過閱讀文件發現可以通過配置使得該外掛在打包時忽略特定的依賴,文件在spring-boot-maven-plugin。
首先備份一下原先的依賴:編譯打包成Flat Jar,然後將BOOT-INF/lib
下的除去ht-*
相關的jar檔案全部解壓出來,另存到libs
目錄下。
接著修改pom.xml
配置如下
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
<!--去除在生產環境中不變的依賴-->
<excludeGroupIds>
org.springframework.boot,
org.springframework,
org.springframework.data,
org.mongodb,
com.github.0604hx,
com.fasterxml.jackson.core,
commons-beanutils,
commons-codec,
org.apache.commons,
org.apache.tomcat.embed,
org.hibernate,
org.slf4j,
com.jayway,
org.jboss,
com.alibaba,
com.fasterxml,
commons-collections,
ch.qos.logback,
org.scala-lang,
org.yaml,
org.jboss.logging,
javax.validation,
nz.net.ultraq.thymeleaf,
org.thymeleaf,
ognl,
org.unbescape,
org.javassist
</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
此時打包好的ht-ui-web.jar
只有117kb這樣
BOOT-INF/lib下只有ht
相關的jar
但是由於沒有其他依賴,ht-ui-web.jar
是不能如期執行起來的
java -jar ht-ui-web-1.0.jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.PropertiesLauncher.main(PropertiesLauncher.java:521)
Caused by: java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
at com.nerve.huotong.web.WebApplication.main(WebApplication.java:21)
... 8 more
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 9 more
至此我們要設定LOADER_PATH
,如下
java -Dloader.path="libs/" -jar ht-ui-web.jar
便可以看到熟悉的Spring Boot 啟動資訊了。
繼續瘦身
上面的專案結構介紹提到了ht-cdn
,我是把前端用到的庫都放在這裡。然後單獨啟動一個Web Application。其他專案需要用到靜態資源就直接使用。
還有另外一個做法是,把resources/public
直接丟到libs
下(就是跟上一步剝離出來的jar包放在一起),結構如下:
這樣也是可以的(不過要注意不能跟真實專案中自己寫的靜態資源重名)。
結語
經過上面的瘦身,每次迭代開發開的Jar包就顯得苗條多了。
插些題外話
Spring Boot 中的 banner.txt
banner是spring boot 應用啟動時列印在控制檯的彩蛋資訊,預設是這樣的
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.3.RELEASE)
想要修改這個文字的話,只需要在resources
下新建banner.txt
即可。這裡可以自定義banner:http://patorjk.com/software/taag