記一次 Maven 打包后,第三方無(wú)法使用的排查記錄
你好,我是悟空。
本文主要內(nèi)容如下:
目錄
前言
最近遇到一個(gè)需求:
寫一個(gè)工具類的 JAR 包,然后提供給第三方調(diào)用其中的類方法。(前提:第三方無(wú)法共用我們項(xiàng)目的私有倉(cāng)庫(kù))
期間遇到了一些問(wèn)題:
- 第三方引入 JAR 包后,無(wú)法import。
- 第三方引入 JAR 包后,缺少 JAR 包中的其他依賴。
本篇做個(gè)記錄,希望能幫助到其他小伙伴。
本篇既然涉及到 Maven,這里先總結(jié)下 Maven 的常用命令。對(duì) Maven 命令比較熟悉的同學(xué)可以跳過(guò)這小節(jié)。
一、Maven 常見(jiàn)命令
當(dāng)我們創(chuàng)建好一個(gè) Maven 工程時(shí),IDEA 開發(fā)工具的右側(cè)就會(huì)自動(dòng)出現(xiàn) Maven 命令。
Maven 操作
我們用鼠標(biāo)雙擊下就可以運(yùn)行了,也可以通過(guò)命令行來(lái)執(zhí)行
下面介紹這幾種命令的區(qū)別。
clean(常用)
刪除項(xiàng)目路徑下的 target 文件,但是不會(huì)刪除本地的maven倉(cāng)庫(kù)已經(jīng)生成的 JAR 文件。
validate
驗(yàn)證工程正確性,所需信息是否完整。
compile
編譯。會(huì)在你的項(xiàng)目路徑下生成一個(gè)target目錄,在該目錄中包含一個(gè)classes文件夾,里面全是生成的class文件。
test
執(zhí)行單元測(cè)試。
package(常用)
將工程文件打包為指定的格式,例如 JAR,WAR 等(看你項(xiàng)目的 pom文件,里面packaging 標(biāo)簽就是來(lái)指定打包類型的)。
這個(gè)命令會(huì)在你的項(xiàng)目路徑下一個(gè)target目錄,并且擁有compile命令的功能進(jìn)行編譯,同時(shí)會(huì)在target目錄下生成項(xiàng)目的 jar/war文件。
如果a項(xiàng)目依賴于b項(xiàng)目,打包b項(xiàng)目時(shí),只會(huì)打包到b項(xiàng)目下target下,編譯a項(xiàng)目時(shí)就會(huì)報(bào)錯(cuò),因?yàn)檎也坏剿蕾嚨腷項(xiàng)目,說(shuō)明a項(xiàng)目在本地倉(cāng)庫(kù)是沒(méi)有找到它所依賴的b項(xiàng)目,這時(shí)就用到 install 命令。
verify
核實(shí),主要是對(duì) package 檢查是否有效、符合標(biāo)準(zhǔn)。
install(常用)
將包安裝至本地倉(cāng)庫(kù),以讓其它項(xiàng)目依賴。
該命令包含了 package 命令功能,不但會(huì)在項(xiàng)目路徑下生成 class 文件和 jar 包,同時(shí)會(huì)在你的本地maven倉(cāng)庫(kù)生成 jar 文件,供其他項(xiàng)目使用(如果沒(méi)有設(shè)置過(guò)maven本地倉(cāng)庫(kù),一般在用戶 /.m2 目錄下。如果 a 項(xiàng)目依賴于 b 項(xiàng)目,那么 install b 項(xiàng)目時(shí),會(huì)在本地倉(cāng)庫(kù)同時(shí)生成 pom 文件和 jar文件,解決了上面打包 package出錯(cuò)的問(wèn)題)。
build
建造。功能類似compile,區(qū)別是對(duì)整個(gè)項(xiàng)目進(jìn)行編譯。
與 compile區(qū)別及特點(diǎn):是對(duì)整個(gè)工程進(jìn)行徹底的重新編譯,而不管是否已經(jīng)編譯過(guò)。
Build過(guò)程往往會(huì)生成發(fā)布包,這個(gè)具體要看對(duì) IDE 的配置了,Build在實(shí)際中應(yīng)用很少,因?yàn)殚_發(fā)時(shí)候基本上不用,發(fā)布生產(chǎn)時(shí)候一般都用ANT等工具來(lái)發(fā)布。Build 因?yàn)橐烤幾g,還要執(zhí)行打包等額外工 作,因此時(shí)間較長(zhǎng)。
site
生成項(xiàng)目的站點(diǎn)文檔。
deploy(常用)
部署。將 jar 包部署到遠(yuǎn)程倉(cāng)庫(kù),通常是私有倉(cāng)庫(kù)。而且包含了 install 命令的功能。
二、打包后,無(wú)法 import?
下面介紹一下我用常規(guī)打包方式遇到的問(wèn)題。
我通過(guò) IDEA 工具創(chuàng)建了一個(gè) SpringBoot 項(xiàng)目,然后 pom.xml 文件中會(huì)自動(dòng)引入一個(gè)打包插件,如下圖所示:
然后我執(zhí)行 maven package 命令,會(huì)在項(xiàng)目的 target 目錄生成一個(gè) JAR 包。如下圖所示:
然后我做了以下事情:
把這個(gè) JAR 包拷貝出來(lái),發(fā)給了第三方。
讓第三方拷貝到他們自己的本地項(xiàng)目中。這里是在項(xiàng)目的根目錄創(chuàng)建了一個(gè) libs 目錄,然后將 jar 包放到 libs 目錄中。
讓第三方在 pom 依賴中引入這個(gè)依賴包。
scope 指定為 system,表示引入指定路徑(systemPath配置)下的 JAR 包。
看起來(lái)這么做沒(méi)問(wèn)題了,但是當(dāng)我們 import 這個(gè) JAR 包下的類時(shí),就會(huì)報(bào)錯(cuò)。如下圖所示:
很奇怪,這里為什么會(huì)報(bào)錯(cuò)呢??
先看下這個(gè) JAR 包是否引入了。如下所示,可以看到確實(shí)是正確引入了,沒(méi)有報(bào)錯(cuò)。
通過(guò) research,發(fā)現(xiàn)這個(gè)打包插件打出來(lái)的 JAR 包,是供執(zhí)行的,也就是可以通過(guò) java -jar 命令來(lái)運(yùn)行這個(gè) JAR 包,并不能給第三方來(lái)引用使用。
解決方案:換一個(gè)打包插件 maven-compiler-plugin。
再次打包發(fā)給第三方,發(fā)現(xiàn) import 不報(bào)錯(cuò)了。
但是又報(bào)另外一個(gè)錯(cuò),我們接著往下看。
三、缺少其他 Jar 包依賴?
報(bào)錯(cuò)信息如下:
通過(guò)這個(gè)信息,可以想到是不是我提供的 JAR 包中引入了這個(gè) commons-codec 依賴,而 JAR 包文件中又不包含這個(gè)依賴。
看下這個(gè) JAR 文件的大小,只有 14 KB, 而 commons-codec 的包大小為 339 KB,說(shuō)明這個(gè) JAR 包確實(shí)不包含 common-codec 依賴。
解決方案:
將其他依賴包打入到這個(gè) JAR 包里面(推薦)。
第三方自己引入其他依賴包。(麻煩了第三方,要第三方一個(gè)個(gè)引入)
那如何將依賴的包打進(jìn)這個(gè) JAR 包里面呢?
這里還要引入一個(gè)打包插件:maven-assembly-plugin,如下所示。(省略了部分標(biāo)簽)
然后還要用插件打包的方式:assembly:assembly
然后target目錄下會(huì)多出一個(gè)包,帶了一個(gè)后綴:jar-with-dependencies
這個(gè)包的文件的大小比較大,有 15.4 M。
發(fā)給第三方再次引入后,不再報(bào)錯(cuò)了。
我們來(lái)看下這個(gè)包里面有什么東西,在 META-INF/maven 目錄下可以看到 commons-codec 依賴包,說(shuō)明確實(shí)將這個(gè)依賴包打進(jìn)去了。
而之前打的包,是沒(méi)有這個(gè)目錄的。
至此,排查結(jié)束。
參考資料:
??https://blog.csdn.net/Shangxingya/article/details/114810454??
??https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html??
關(guān)于我
8 年互聯(lián)網(wǎng)開發(fā)經(jīng)驗(yàn),擅長(zhǎng)微服務(wù)、分布式、架構(gòu)設(shè)計(jì)。目前在一家大型上市公司從事基礎(chǔ)架構(gòu)和性能優(yōu)化工作。
InfoQ 簽約作者、藍(lán)橋簽約作者、阿里云專家博主、51CTO 紅人。