天天看點

Spring Boot運作的Jar包瘦身實踐!

往期熱門文章:

1、BAT、TMD程式員的工位标配,竟是這塊滑鼠墊?粉絲包郵送200套!2、徹底搞懂 Nginx 的五大應用場景3、SpringBoot+Dubbo是如何搞定微服務,成功應對高并發的?4、為什麼有些大公司技術弱爆了?5、這 40 道 Redis 面試題讓你不再慌(附答案)
           

   作者:內建顯示卡

   blog.csdn.net/ssrc0604hx/article/details/54175027

背景

随着Spring Boot的流行,越來越多開發者選擇使用Spring Boot來釋出Web應用。不同于傳統的War包釋出,Spring Boot把整個項目打包成一個可運作的Jar包(即所謂的Flat Jar),導緻了這個Jar包很大(通常有40M+)。如今疊代釋出時常有的事情,每次都上傳一個如此龐大的檔案,會浪費很多時間。

下面就以一個小項目為例,簡述小弟所用的瘦身方案。當然如果是内網釋出或者你用的寬帶異常給力,瘦身就沒有多大意義了。

實踐

項目簡介

建立一個練習用的項目,其結構如下

Spring Boot運作的Jar包瘦身實踐!
  • ht-cdn

    存放的是靜态資源(如第三方js、css、images等)
  • ht-domain

    項目中的資料實體定義
  • ht-repository

    資料層接口及實作
  • ht-service

    業務邏輯接口及實作
  • ht-ui-webWeb

    管理

其中

ht-ui-web

依賴于

ht-domain

ht-repository

ht-service

,實作了一個簡單的GetMapping。

接着打包項目,整個jar包24M這樣

Spring Boot運作的Jar包瘦身實踐!

瘦身準備

首先我們要對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這樣

Spring Boot運作的Jar包瘦身實踐!

BOOT-INF/lib

下隻有ht相關的jar

Spring Boot運作的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包放在一起),結構如下:

Spring Boot運作的Jar包瘦身實踐!

這樣也是可以的(不過要注意不能跟真實項目中自己寫的靜态資源重名)。

結語

經過上面的瘦身,每次疊代開發開的Jar包就顯得苗條多了。

插些題外話

Spring Boot 中的

banner.txt

banner是spring boot 應用啟動時列印在控制台的彩蛋資訊,預設是這樣的

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.3.RELEASE)

           

想要修改這個文本的話,隻需要在resources下建立

banner.txt

即可。

這裡可以自定義banner:

http://patorjk.com/software/taag/
Spring Boot運作的Jar包瘦身實踐!
最近熱文閱讀:

1、BAT、TMD程式員的工位标配,竟是這塊滑鼠墊?粉絲包郵送200套!
2、徹底搞懂 Nginx 的五大應用場景
3、推薦60個相見恨晚的神器工具
4、為什麼有些大公司技術弱爆了?
5、這 40 道 Redis 面試題讓你不再慌(附答案)
6、優秀的代碼都是如何分層的?
7、IDEA 中的熱部署神器!
8、SpringBean預設是單例的,高并發情況下,如何保證并發安全?
9、知乎高贊:拼多多和國家電網,選哪個?
10、Windows 11 全網曝光,果然一股子蘋果味...

關注公衆号,你想要的Java都在這裡