javascript
Spring Boot 项目瘦身指南,瘦到不可思议!129M->1.3M
之前在 從使用傳統(tǒng)Web框架到切換到Spring Boot后的總結(jié) 中提到關(guān)于 Spring Boot 編譯打包,Spring Boot 應(yīng)用程序不用額外部署到外部容器中,可以直接通過(guò) Maven 命令將項(xiàng)目編譯成可執(zhí)行的 jar 包,然后通過(guò) java -jar 命令啟動(dòng)即可,非常方便。
最近有小伙伴私信我說(shuō),打 jar 包方便是方便,就是每次打包出來(lái)的 jar 太大了,先不說(shuō)上傳時(shí)間的問(wèn)題,如果只修改了 1 個(gè)類就需要重新打包項(xiàng)目,然后重新上傳項(xiàng)目到服務(wù)器,怎么覺得還不如我之前使用 war 包方便呢,使用 war 包時(shí),雖然要部署到 Tomcat 中,但只需要將修改的 class 替換一下,重啟一下 Tomcat 就可以了。。。
其實(shí)到底選擇哪種打包方式,主要還是看個(gè)人習(xí)慣和業(yè)務(wù)場(chǎng)景需求,畢竟 Spring Boot 也支持打包 war 包的。
今天的重點(diǎn)不是打包方式,而是解決困惑了小伙伴打包的 jar 太大的問(wèn)題。
正常打包項(xiàng)目
給 Spring Boot 打包大家應(yīng)該很熟了吧,只需要在 pom.xml 文件中配置 spring-boot-maven-plugin 打包插件:
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins> </build>然后在項(xiàng)目根目錄執(zhí)行 mvn clean pavkage 就可以完成打包了,如下是我本地的一個(gè)項(xiàng)目打包情況:
可以看到打包出的 jar 應(yīng)用是相當(dāng)?shù)拇罅?#xff0c;如小伙伴說(shuō)的一樣,如果每次修改一個(gè) class 文件或者配置文件,就需要重新打包然后上傳服務(wù)器的話,那確實(shí)是太麻煩了,可能上傳就浪費(fèi)大部分時(shí)間。。。
應(yīng)用瘦身(分離lib和配置文件)
其實(shí) jar 包大的原因在于所有的依賴包全部集成在 jar 包里面,如下是瘦身前的 jar 包內(nèi)部結(jié)構(gòu):
其中 classes 就是我們項(xiàng)目的代碼,僅僅1.3M,而 129MB 的 lib 目錄是項(xiàng)目中所有的依賴(比如spinrg、Hibernate等依賴),如果我們能把這個(gè) lib 目錄提取出來(lái),整個(gè)項(xiàng)目就會(huì)變得特別小了。說(shuō)干就干。
我們知道 Spring Boot 的打包終究是依賴于 Maven ,所以想到更改打包信息,無(wú)非就是指定 Maven 的配置。
在 pom.xml 添加如下信息(后文解釋):
<build><finalName>你想要的jar包名稱</finalName><plugins><!-- 1、編譯出不帶 lib 文件夾的Jar包 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><!--表示編譯版本配置有效--><fork>true</fork><!--引入第三方j(luò)ar包時(shí),不添加則引入的第三方j(luò)ar不會(huì)被打入jar包中--><includeSystemScope>true</includeSystemScope><!--排除第三方j(luò)ar文件--><includes><include><groupId>nothing</groupId><artifactId>nothing</artifactId></include></includes></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin><!-- 2、完成對(duì)Java代碼的編譯,可以指定項(xiàng)目源碼的jdk版本,編譯后的jdk版本,以及編碼 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><!-- 源代碼使用的JDK版本 --> <source>${java.version}</source><!-- 需要生成的目標(biāo)class文件的編譯版本 --><target>${java.version}</target><!-- 字符集編碼 --><encoding>UTF-8</encoding><!-- 用來(lái)傳遞編譯器自身不包含但是卻支持的參數(shù)選項(xiàng) --> <compilerArguments><verbose/><!-- windwos環(huán)境(二選一) --><bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath><!-- Linux環(huán)境(二選一) --><bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath></compilerArguments></configuration></plugin><!-- 3、將所有依賴的jar文件復(fù)制到target/lib目錄 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><executions><execution><id>copy-dependencies</id><phase>prepare-package</phase><goals><goal>copy-dependencies</goal></goals><configuration><!--復(fù)制到哪個(gè)路徑,${project.build.directory} 缺醒為 target,其他內(nèi)置參數(shù)見下面解釋--><outputDirectory>${project.build.directory}/lib</outputDirectory><overWriteReleases>false</overWriteReleases><overWriteSnapshots>false</overWriteSnapshots><overWriteIfNewer>true</overWriteIfNewer></configuration></execution></executions></plugin><!-- 4、指定啟動(dòng)類,指定配置文件,將依賴打成外部jar包 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><configuration><archive><manifest><!-- 是否要把第三方j(luò)ar加入到類構(gòu)建路徑 --><addClasspath>true</addClasspath><!-- 外部依賴jar包的最終位置 --><classpathPrefix>lib/</classpathPrefix><!-- 項(xiàng)目啟動(dòng)類 --><mainClass>com.javam4.MyApplication</mainClass></manifest></archive><!--資源文件不打進(jìn)jar包中,做到配置跟項(xiàng)目分離的效果--><excludes><!-- 業(yè)務(wù)jar中過(guò)濾application.properties/yml文件,在jar包外控制 --><exclude>*.properties</exclude><exclude>*.xml</exclude><exclude>*.yml</exclude></excludes></configuration></plugin></plugins> </build>如下一一細(xì)拆如上配置:
1、spring-boot-maven-plugin
Springboot 默認(rèn)使用 spring-boot-maven-plugin 來(lái)打包,這個(gè)插件會(huì)將項(xiàng)目所有的依賴打入項(xiàng)目 jar 包里面,正常打包時(shí) spring-boot-maven-plugin 結(jié)構(gòu)如下:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.javam4.MyApplication</mainClass> <layout>ZIP</layout> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin>如下是提取的修改項(xiàng):
<configuration><!--表示編譯版本配置有效--><fork>true</fork><!--引入第三方j(luò)ar包時(shí),不添加則引入的第三方j(luò)ar不會(huì)被打入jar包中--><includeSystemScope>true</includeSystemScope><!--排除第三方j(luò)ar文件--><includes><include><groupId>nothing</groupId><artifactId>nothing</artifactId></include></includes> </configuration>修改的作用:
- includeSystemScope:jar包分兩種,一種是spring、mybatis等這種項(xiàng)目依賴的,再就是我們外部手動(dòng)引入的第三方 jar 依賴,如果該參數(shù)不設(shè)置為 true 的話是不能被打包進(jìn)來(lái)的~
- includes:這個(gè)節(jié)點(diǎn)就是排除項(xiàng)目中所有的 jar,那還怎么打包?
其實(shí)我們需要將打包插件替換為 maven-jar-plugin,然后使用該插件拷貝依賴到 jar 到外面的 lib 目錄。
2、maven-xxx-plugin
從 2、3、4 你會(huì)發(fā)現(xiàn)用到了 maven-xxx-plugin 格式的三種插件,簡(jiǎn)單說(shuō)一下這三者的作用:
-
maven-compiler-plugin:
完成對(duì)Java代碼的編譯,可以指定項(xiàng)目源碼的jdk版本、編譯后的jdk版本,以及編碼,如果不寫這個(gè)插件也是沒問(wèn)題的,不寫會(huì)使用默認(rèn)的 jdk 版本來(lái)處理,只是這樣容易出現(xiàn)版本不匹配的問(wèn)題,比如本地maven環(huán)境用的3.3.9版本,默認(rèn)會(huì)使用jdk1.5進(jìn)行編譯,而項(xiàng)目中用的jdk1.8的編譯環(huán)境,那就會(huì)導(dǎo)致打包時(shí)編譯不通過(guò)。
-
maven-dependency-plugin:
作用就是將所有依賴的jar文件復(fù)制到指定目錄下,其中涉及到的 ${project.xx} 見下文補(bǔ)充。
-
maven-jar-plugin:
主要作用就是將maven工程打包成jar包。
主要說(shuō)一下 maven-jar-plugin 插件的如下配置:
<configuration><!--資源文件不打進(jìn)jar包中,做到配置跟項(xiàng)目分離的效果--><excludes><!-- 業(yè)務(wù)jar中過(guò)濾application.properties/yml文件,在jar包外控制 --><exclude>*.properties</exclude><exclude>*.xml</exclude><exclude>*.yml</exclude></excludes> </configuration>打包時(shí)排除資源配置文件,如果排除了配置文件那么項(xiàng)目啟動(dòng)是怎么讀取呢?
配置文件有這么一個(gè)默認(rèn)的優(yōu)先級(jí):
當(dāng)前項(xiàng)目config目錄下 > 當(dāng)前項(xiàng)目根目錄下 > 類路徑config目錄下 > 類路徑根目錄下
因此只需要將配置文件復(fù)制一份到與 jar 包平級(jí)目錄下,或者與jar包平行config目錄下,就能優(yōu)先使用此配置文件,達(dá)到了偽分離目的。
最終的目錄結(jié)構(gòu)如下:
Maven 中的內(nèi)置變量說(shuō)明:
- ${basedir} 項(xiàng)目根目錄
- ${project.build.directory} 構(gòu)建目錄,缺省為target
- ${project.build.outputDirectory} 構(gòu)建過(guò)程輸出目錄,缺省為target/classes
- ${project.build.finalName} 產(chǎn)出物名稱,缺省為{project.artifactId}-${project.version}
- ${project.packaging} 打包類型,缺省為jar
- ${project.packaging} 打包類型,缺省為jar
- ${project.xxx} 當(dāng)前pom文件的任意節(jié)點(diǎn)的內(nèi)容
瘦身總結(jié)
Spring Boot 框架提供了一套自己的打包機(jī)制 — spring-boot-maven-plugin,Springboot 默認(rèn)使用該插件來(lái)打包,打包時(shí)會(huì)將項(xiàng)目所有的依賴打入項(xiàng)目 jar 包里面,如果我們想要抽離依賴的 jar 僅僅使用該插件是不行的,就需要將打包插件替換為 maven-jar-plugin,并拷貝所有的依賴到 jar 外面的 lib 目錄。
項(xiàng)目打包時(shí),在分離依賴 jar 包基礎(chǔ)上,我們又排除了配置文件,因?yàn)榕渲梦募幸粋€(gè)默認(rèn)的讀取路徑:
當(dāng)前項(xiàng)目config目錄下 > 當(dāng)前項(xiàng)目根目錄下 > 類路徑config目錄下 > 類路徑根目錄下
我們只需要在當(dāng)前項(xiàng)目 jar 包同級(jí)目錄創(chuàng)建一個(gè) config 文件夾,然后將配置文件復(fù)制一份,這樣就達(dá)到了偽分離目的。
之后再修改配置文件,比如端口號(hào)、數(shù)據(jù)庫(kù)連接信息等,就不需要重新打包項(xiàng)目了,直接修改完配置文件重啟項(xiàng)目就可以了。
而經(jīng)過(guò)分離依賴后的 jar 包從原來(lái)的100多兆到現(xiàn)在的1兆,如果后面需要變更業(yè)務(wù)邏輯,只需要輕量的編譯項(xiàng)目,快速的實(shí)現(xiàn)項(xiàng)目的上傳替換,有效的減少了網(wǎng)絡(luò)開銷,提高項(xiàng)目部署的效率。
博客地址:https://niceyoo.cnblogs.com
更多原創(chuàng)內(nèi)容可以移步我的公眾號(hào),回復(fù)「面試」獲取我整理的2020面經(jīng)。
總結(jié)
以上是生活随笔為你收集整理的Spring Boot 项目瘦身指南,瘦到不可思议!129M->1.3M的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python bool值要注意的一些地方
- 下一篇: 从使用传统Web框架到切换到Spring