給你的SpringBoot打的jar包瘦瘦身

Spring boot默認方式打包因爲打的是全量依賴包(也稱爲fat包),不但打包慢,體積大,傳輸也慢,今天教你們給spring boot瘦瘦身。java

背景

如今微服務架構愈來愈流行,一個項目10多個基於spring boot的服務模塊很常見。假設一個服務模塊打成jar包是100M,那麼一次全量發佈可能就須要上傳1G的文件。在網絡狀況好的時候可能還沒多大感受,但若是是代碼須要拷貝到內網發佈,或者上傳到某些國外服務器上, 將嚴重影響工做效率。web

那麼,有沒有什麼辦法給咱們打的spring boot的jar包瘦瘦身呢?
答案是有,經過相關配置使spring boot打包的時候只加載一些常常會變化的依賴包,好比項目通用的common模塊,一些調用feign接口的API模塊等,而那些固定的不多變化的依賴包則直接上傳到服務器的指定目錄下,在項目啓動的時候經過命令指定lib包加載的目錄就能夠了。這樣,咱們打出來的jar包最多幾M不到,極大的縮小了spring boot項目jar包的體積,提升了發佈上線的效率。算法

補充:
fat jar:  即胖包,打出的jar包包含全部的依賴包。
好處是能夠直接運行,不須要添加其餘命令,壞處是體積太大,傳輸困難。spring

thin jar:即瘦包,打出的jar包只包含一些常常變換的依賴包,通常爲項目中的公共模塊或一些API接口依賴模塊。
好處是體積小,有利於提升項目發佈效率;
壞處是依賴包外置可能存在安全患,若是項目的maven依賴變更頻繁,維護服務器上的lib目錄就比較麻煩,也不利於問題定位。tomcat

瘦身運動

一、修改maven打包參數安全

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layout>ZIP</layout>
                     <includes>
                         <include>
                             <groupId>nothing</groupId>
                             <artifactId>nothing</artifactId>
                         </include>
                         <include>
                             <groupId>com.huacloud.tax.rpc</groupId>
                             <artifactId>common</artifactId>
                         </include>
                     </includes>
                </configuration>
            </plugin>
        </plugins>

    </build>

說明:服務器

layout 置可執行jar包中Main-Class的類型,這裏必定要設置爲  ZIP,使打的jar包中的Main-Class爲PropertiesLauncher 。微信

includes網絡

將須要保留的jar包,按照groupId和artifactId(注意兩個都是必填項)include進來。
nothing 表明不存在的依賴包,意思就是什麼依賴包都不引入
common是引入的公共服務模塊。架構

二、執行maven打包
先執行mvn clean,而後執行mvn package

將target目錄下打好的包複製到D:\web目錄下,重命名爲tax-ws-thin-zip.jar。

經過壓解工具查看tax-ws-thin-zip.jar裏面META-INF目錄下的MANIFEST.MF文件:

發現Main-Class的值確實變爲了PropertiesLauncher ,說明咱們的配置成功。
(至於爲何必定要將Main-Class配置爲PropertiesLauncher 後面再介紹)

三、比較FatJar和ThinJar的體積:


tax-ws-fat.jar是沒有修改配置前打的全量依賴包。
能夠發現,tax-ws-thin.jar這個瘦包的體積比胖包的體積小了很是多。

四、從fatJar包中拷貝中lib包到D:\web目錄下

五、經過命令啓動jar包
D:\web>java -Dloader.path="D:\web\lib"  -jar tax-ws-thin.jar

經過啓動參數loader.path配置外置依賴包的加載路徑。

項目成功啓動,說明咱們配置的外包依賴包加載生效。

原理探究

爲何將可執行jar包的Main-Class設置爲PropertiesLauncher就能夠經過配置啓動參數loader.path指定依賴包的加載路徑呢?
首先咱們對spring boot可執行jar包實現原理中的啓動器Launcher有所瞭解。

如下摘自spring boot官網:
org.springframework.boot.loader.Launcher類是特殊的引導程序類,用做可執行jar的主要入口點。它是jar文件中的實際Main-Class,用於設置適當的URLClassLoader並最終調用main()方法。

有三個啓動器子類(JarLauncher,WarLauncher和PropertiesLauncher)。它們的目的是從目錄中的嵌套jar文件或war文件(而不是在類路徑中顯式的文件)加載資源(.class文件等)。對於JarLauncher和WarLauncher,嵌套路徑是固定的。JarLauncher位於BOOT-INF / lib /中,而WarLauncher位於WEB-INF / lib /和WEB-INF / lib-provided /中。若是須要,能夠在這些位置添加額外的罐子。默認狀況下,PropertiesLauncher在您的應用程序存檔中的BOOT-INF / lib /中查找。您能夠經過在loader.properties(這是目錄,歸檔文件或歸檔文件中的目錄的逗號分隔列表)中設置一個稱爲LOADER_PATH或loader.path的環境變量來添加其餘位置。
————————————————

也就是說啓動器Launcher是爲了項目啓動加載依賴資源的,共有3個啓動器(JarLauncher,WarLauncher和PropertiesLauncher),其中JarLauncher和WarLauncher加載資源的路徑是固定的,而PropertiesLauncher能夠經過環境變量loader.path來指定加載資源的位置。

layout屬性值說明:

JAR,即一般的可執行jar
Main-Class: org.springframework.boot.loader.JarLauncher

WAR,即一般的可執行war,須要的servlet容器依賴位於
Main-Class: org.springframework.boot.loader.warLauncher

ZIP,即DIR,相似於JAR
Main-Class: org.springframework.boot.loader.PropertiesLauncher
(記住這個就好,其餘的應用場景比較少)

PropertiesLauncher屬性配置

PropertiesLauncher具備一些能夠經過外部屬性(系統屬性,環境變量,清單條目或loader.properties)啓用的特殊功能。下表描述了這些屬性:

Key 目的
loader.path lib包加載路徑
loader.home 用於解析loader.path中的相對路徑
loader.args main方法的默認參數(以空格分隔)。
loader.main 要啓動的主類的名稱(例如com.app.Application)
loader.config.name 屬性文件的路徑(例如,classpath:loader.properties)。默認爲loader.properties。
loader.system 布爾值標誌,指示應將全部屬性添加到系統屬性。默認爲false。

更過資料能夠查看官網的關於spring boot可執行jar包的說明文檔:The Executable Jar Format

陷阱糾正

以前在網上看到過一種沒有配置layout=ZIP的方式,而是直接打成瘦包後,在啓動命令中經過-Djava.ext.dirs來指定外置依賴包的加載路徑。

D:\web>java -Djava.ext.dirs="D:\web\lib"  -jar tax-ws-thin.jar

原理解析:
-Djava.ext.dirs會覆蓋Java自己的ext設置,java.ext.dirs指定的目錄由ExtClassLoader加載器加載,若是您的程序沒有指定該系統屬性,那麼該加載器默認加載JAVA_HOME/jre/lib/ext目錄下的全部jar文件。但若是你手動指定系統屬性且忘了把JAVA_HOME/jre/lib/ext路徑給加上,那麼ExtClassLoader不會去加載JAVA_HOME/lib/ext下面的jar文件,這意味着你將失去一些功能,例如java自帶的加解密算法實現。

因此,經過這種寫法,直接強行修改java默認擴展類加載器的加載路徑,很容易致使一些問題。最好不要隨便使用。

擴展:雙親委派機制

這裏展開來說就涉及到了java的雙親委派加載機制。

一、BootStrapClassLoader:啓動類加載器。

JAVA_HOME/jre/lib/ext下的類庫(或者經過參數-Djava.ext.dirs指定)。

三、AppClassLoader:應用程序加載器,會加載java環境變量CLASSPATH所指定的路徑下的類庫,而CLASSPATH所指定的路徑能夠經過Systemn.getProperty("java.class.path")獲取,該變量能夠覆蓋。

四、CustomClassLoader:自定義加載器,就是用戶本身定義的CLassLoader,好比tomcat的standardClassLoader屬於這一類。

ClassLoader雙親委派機制:
一、當APPClassLoader加載一個class時,它首先不會本身去加載這個類,而是把類加載請求委派給父類加載器EXTClassloader去完成。

二、當EXTClassLoader加載一個class時,它首先不會去嘗試加載這個類,而是把類加載請求委派給BootStrapClassLoader去完成。

三、若是BottStrapClassLoader加載失敗,會使用EXTClassLoader去嘗試加載。

四、若EXTClassLoader也加載失敗,則會使用APPClassLoader來加載,若是APPClassLoader也加載失敗,則會報出異常ClassNotFundException.

找不到Oracle驅動包的問題

在使用-Djava.ext.dirs=./lib指定外置依賴包的時候,發現加載不到Oracle鏈接的驅動包,這個時候須要添加
-Doracle.jdbc.thinLogonCapability=o3,配置oracle的登陸兼容性

總結

一、爲何要給spring boot工程打的可執行jar包瘦身
二、spring boot的三種啓動器說明
三、如何配置PropertiesLauncher啓動器實現外部依賴包的加載
四、指出了經過指定-Djava.ext.dirs參數實現外部依賴包加載的問題
五、擴展說明了java的雙親委派加載機制
六、外部依賴包加載不到Oracle驅動包的解決辦法

最後

感謝你們最近的支持,雖然說學習是本身的事,可是看見你們的點贊、評論和關注,真的很使人鼓舞,謝謝你們。
我會繼續努力,分享更多優質的技術文章,但願和你們一塊兒交流成長。


更多精彩,關注我吧。

圖注:跟着老萬學java



本文分享自微信公衆號 - 跟着老萬學java(douzhe_2019)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索