目打包外部Jar依賴的4種方案與最佳實(shí)踐)
1. 項(xiàng)目概述當(dāng)Spring Boot遇上“非主流”依賴在Java后端開發(fā)尤其是Spring Boot項(xiàng)目里Maven幾乎是我們管理依賴的“標(biāo)準(zhǔn)答案”。pom.xml里寫幾個(gè)坐標(biāo)mvn clean package一下一個(gè)包含所有依賴的可執(zhí)行Jar包就生成了干凈利落。但現(xiàn)實(shí)往往比理想骨感。你有沒有遇到過這種情況項(xiàng)目需要集成某個(gè)老舊的、公司內(nèi)部開發(fā)的、或者壓根就沒上傳到Maven中央倉(cāng)庫(kù)或任何私有倉(cāng)庫(kù)的第三方SDK它通常以幾個(gè).jar文件的形式提供靜靜地躺在你項(xiàng)目的/lib目錄下。這時(shí)候常規(guī)的dependency聲明就失效了直接打包這些外部Jar十有八九會(huì)被排除在最終的產(chǎn)物之外運(yùn)行時(shí)就是經(jīng)典的ClassNotFoundException。這個(gè)標(biāo)題“springboot用maven打包外部引入的lib依賴”直指的就是這個(gè)讓很多開發(fā)者特別是剛接手遺留系統(tǒng)或需要對(duì)接特定硬件、專有協(xié)議SDK的同行們頭疼的問題。它不是一個(gè)簡(jiǎn)單的配置問題而是涉及Maven生命周期、依賴作用域、打包插件機(jī)制以及最終可執(zhí)行Jar包結(jié)構(gòu)的綜合課題。解決它意味著你的Spring Boot應(yīng)用真正具備了“包容性”能夠無縫整合任何形態(tài)的Java庫(kù)無論它來自喧囂的開源世界還是安靜的本地文件夾。2. 核心思路與方案選型不止一種“打包”方式面對(duì)本地lib目錄下的Jar文件我們的目標(biāo)很明確讓Maven在編譯compile、測(cè)試test和打包package階段都能識(shí)別并使用它們并最終將其打入Spring Boot的可執(zhí)行Jar中。圍繞這個(gè)目標(biāo)主要有以下幾種主流思路每種都有其適用場(chǎng)景和優(yōu)缺點(diǎn)。2.1 方案一安裝到本地Maven倉(cāng)庫(kù)mvn install:install-file這是最“Maven原生”的做法。通過命令行或IDE將本地Jar文件“安裝”到你的本地倉(cāng)庫(kù)通常是~/.m2/repository中使其變成一個(gè)標(biāo)準(zhǔn)的、可通過坐標(biāo)引用的依賴。操作邏輯你手動(dòng)為這個(gè)Jar分配一個(gè)groupId、artifactId和version比如com.company:legacy-sdk:1.0.0然后執(zhí)行安裝命令。之后就可以像引用其他依賴一樣在pom.xml中聲明它。為什么選擇它標(biāo)準(zhǔn)化完全遵循Maven的依賴管理哲學(xué)項(xiàng)目配置最干凈。團(tuán)隊(duì)協(xié)作如果所有開發(fā)人員都執(zhí)行了相同的安裝命令那么大家的本地環(huán)境就是一致的。也可以通過腳本將此步驟自動(dòng)化。依賴傳遞如果這個(gè)本地Jar本身還依賴其他Jar并且你一起安裝了Maven可以正常處理傳遞性依賴。為什么不總是它環(huán)境隔離性差本地倉(cāng)庫(kù)是用戶全局的。不同項(xiàng)目可能需要同一個(gè)Jar的不同版本容易造成沖突。構(gòu)建可移植性在新環(huán)境如CI/CD服務(wù)器上構(gòu)建時(shí)必須確保安裝步驟被執(zhí)行否則構(gòu)建失敗。這增加了構(gòu)建流程的復(fù)雜度。“污染”本地倉(cāng)庫(kù)安裝了大量臨時(shí)或項(xiàng)目專用的Jar后本地倉(cāng)庫(kù)會(huì)變得臃腫清理不便。2.2 方案二引用系統(tǒng)作用域依賴system scopeMaven提供了system作用域允許你直接引用文件系統(tǒng)上某個(gè)特定路徑的Jar包。操作邏輯在pom.xml中通過systemPath標(biāo)簽指定Jar文件的絕對(duì)或相對(duì)路徑并設(shè)置scope為system。為什么選擇它直觀簡(jiǎn)單配置直接指向文件一目了然。項(xiàng)目自包含可以將Jar文件放入項(xiàng)目目錄如/libs隨項(xiàng)目代碼一起版本控制實(shí)現(xiàn)了真正的“開箱即建”。避免污染倉(cāng)庫(kù)完全不依賴本地或遠(yuǎn)程倉(cāng)庫(kù)。為什么不總是它可移植性陷阱systemPath中的路徑是硬編碼的。如果路徑是絕對(duì)的如C:\libs\foo.jar在其他機(jī)器上必然失敗。即使是相對(duì)路徑也需要所有開發(fā)者保持相同的項(xiàng)目目錄結(jié)構(gòu)。依賴傳遞失效system作用域的依賴不會(huì)被傳遞。也就是說如果你的項(xiàng)目A依賴了system范圍的Jar那么依賴項(xiàng)目A的項(xiàng)目B將不會(huì)自動(dòng)獲得這個(gè)Jar。不被推薦Maven官方文檔已不推薦使用system作用域因?yàn)樗茐牧薓aven依賴管理的一致性。2.3 方案三使用Maven依賴插件maven-dependency-plugin復(fù)制這個(gè)思路是“曲線救國(guó)”在打包階段使用插件將lib目錄下的Jar文件復(fù)制到Spring Boot打包插件spring-boot-maven-plugin所期望的目錄中從而將其包含進(jìn)最終的可執(zhí)行Jar。操作邏輯配置maven-dependency-plugin在prepare-package階段即在spring-boot-maven-plugin打包之前將指定目錄的Jar文件復(fù)制到target/classes/lib或target/dependency這樣的臨時(shí)目錄。為什么選擇它非侵入性不需要修改本地倉(cāng)庫(kù)也不需要在pom.xml中聲明偽依賴。靈活性強(qiáng)可以精細(xì)控制哪些Jar被復(fù)制以及復(fù)制到哪里。與構(gòu)建生命周期集成是標(biāo)準(zhǔn)的Maven插件操作流程清晰。為什么不總是它僅作用于打包該Jar在編譯和測(cè)試階段不可見。如果你的代碼在編譯時(shí)就需要用到這些Jar中的類此方案行不通。配置稍復(fù)雜需要理解Maven生命周期階段并正確配置插件執(zhí)行目標(biāo)goal和階段phase。2.4 方案四創(chuàng)建自定義模塊并打包安裝推薦這是我認(rèn)為最健壯、最符合工程化實(shí)踐的方式。為這些本地Jar單獨(dú)創(chuàng)建一個(gè)Maven模塊子模塊在該模塊的pom.xml中使用maven-install-plugin在構(gòu)建時(shí)自動(dòng)將其“安裝”到本地倉(cāng)庫(kù)或者使用maven-deploy-plugin部署到私有倉(cāng)庫(kù)。主Spring Boot模塊再像引用普通依賴一樣引用它。操作邏輯創(chuàng)建一個(gè)新的Maven項(xiàng)目例如third-party-libs。將其打包類型packaging設(shè)為pom。在該模塊的pom.xml中使用build-helper-maven-plugin將lib文件夾附加為資源并配置maven-install-plugin在install階段將每個(gè)Jar安裝到本地倉(cāng)庫(kù)。在主Spring Boot模塊中依賴這個(gè)third-party-libs模塊。為什么強(qiáng)烈推薦它一勞永逸一次配置團(tuán)隊(duì)所有成員以及CI/CD環(huán)境都能直接使用無需額外手動(dòng)步驟。真正的依賴管理享受完整的Maven特性如版本管理、依賴傳遞如果配置得當(dāng)、依賴排除等。清晰的項(xiàng)目結(jié)構(gòu)將第三方庫(kù)的管理與業(yè)務(wù)代碼分離職責(zé)清晰。可擴(kuò)展性未來如果要將這些庫(kù)部署到公司私有Nexus或Artifactory遷移成本極低。注意對(duì)于大多數(shù)需要在編譯期就使用這些外部Jar的Spring Boot項(xiàng)目方案一手動(dòng)安裝和方案四創(chuàng)建模塊是唯二可行的選擇。方案二system scope雖然編譯期可用但弊端明顯。方案三僅適用于運(yùn)行時(shí)依賴。下文將重點(diǎn)詳解方案一和方案四的實(shí)操因?yàn)樗鼈兪墙鉀Q核心問題的關(guān)鍵。3. 核心實(shí)操兩種主流方案的詳細(xì)實(shí)現(xiàn)接下來我們深入兩種最實(shí)用方案的配置細(xì)節(jié)我會(huì)結(jié)合自己的踩坑經(jīng)驗(yàn)把每一步都講透。3.1 方案一實(shí)操手動(dòng)安裝到本地倉(cāng)庫(kù)假設(shè)我們有一個(gè)外部Jar包payment-gateway-sdk-2.1.0.jar存放在項(xiàng)目根目錄的/lib文件夾下。步驟1確定Maven坐標(biāo)你需要為這個(gè)Jar發(fā)明一個(gè)坐標(biāo)。這需要和提供Jar的團(tuán)隊(duì)或你自己約定好盡量遵循公司域名反轉(zhuǎn).項(xiàng)目名:模塊名:版本號(hào)的規(guī)范。例如groupId:com.example.sdkartifactId:payment-gatewayversion:2.1.0packaging:jar步驟2執(zhí)行安裝命令打開終端或IDE的Terminal導(dǎo)航到lib目錄或者使用Jar的絕對(duì)路徑。執(zhí)行以下Maven命令mvn install:install-file \ -Dfilepayment-gateway-sdk-2.1.0.jar \ -DgroupIdcom.example.sdk \ -DartifactIdpayment-gateway \ -Dversion2.1.0 \ -Dpackagingjar \ -DgeneratePomtrue參數(shù)拆解與避坑-Dfile: Jar文件路徑。強(qiáng)烈建議使用相對(duì)路徑如./lib/payment-gateway-sdk-2.1.0.jar以保證命令在不同環(huán)境下的可執(zhí)行性。-DgeneratePomtrue: 讓Maven自動(dòng)生成一個(gè)基本的pom.xml文件并安裝到倉(cāng)庫(kù)。這對(duì)于沒有源碼和POM的純Jar文件非常有用。如果該SDK提供了POM文件你可以使用-DpomFile參數(shù)指定它這樣能保留其原始的依賴關(guān)系。執(zhí)行位置命令可以在任何位置執(zhí)行只要-Dfile的路徑正確。我習(xí)慣在Jar文件所在目錄執(zhí)行這樣路徑最簡(jiǎn)單。權(quán)限問題在Linux/Mac系統(tǒng)下確保你對(duì)本地Maven倉(cāng)庫(kù)目錄~/.m2/repository有寫權(quán)限。步驟3在pom.xml中引用安裝成功后在Spring Boot項(xiàng)目的pom.xml中像添加普通依賴一樣添加它dependency groupIdcom.example.sdk/groupId artifactIdpayment-gateway/artifactId version2.1.0/version /dependency步驟4驗(yàn)證與打包執(zhí)行mvn clean compile應(yīng)該能順利編譯。之后執(zhí)行mvn clean package使用jar tf target/your-app.jar | grep payment-gatewayLinux/Mac或直接解壓查看BOOT-INF/lib/目錄確認(rèn)該Jar已被打包進(jìn)去。實(shí)操心得對(duì)于團(tuán)隊(duì)項(xiàng)目務(wù)必在README.md或構(gòu)建腳本中明確記錄這個(gè)手動(dòng)安裝步驟。更好的做法是編寫一個(gè)Shell腳本install-libs.sh或批處理文件install-libs.bat將安裝命令固化下來新成員拉取代碼后只需運(yùn)行一下腳本即可。3.2 方案四實(shí)操創(chuàng)建自定義模塊自動(dòng)化管理這個(gè)方案稍微復(fù)雜但更優(yōu)雅適合管理多個(gè)外部Jar或需要團(tuán)隊(duì)協(xié)作的場(chǎng)景。步驟1創(chuàng)建模塊目錄結(jié)構(gòu)在Spring Boot項(xiàng)目的根目錄下與主模塊pom.xml同級(jí)創(chuàng)建一個(gè)新的目錄例如third-party-libs。在里面初始化一個(gè)標(biāo)準(zhǔn)的Maven項(xiàng)目結(jié)構(gòu)your-springboot-project/ ├── pom.xml (主模塊) ├── src/ ├── third-party-libs/ │ ├── pom.xml │ ├── lib/ │ │ ├── payment-gateway-sdk-2.1.0.jar │ │ └── legacy-utils-1.0.0.jar │ └── (其他Maven標(biāo)準(zhǔn)目錄) └── ...步驟2配置third-party-libs模塊的pom.xml這是最關(guān)鍵的一步。third-party-libs/pom.xml內(nèi)容如下?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion groupIdcom.yourcompany/groupId artifactIdthird-party-libs/artifactId version1.0.0/version packagingpom/packaging !-- 打包類型為pom -- build plugins !-- 插件1將lib目錄下的jar附加到項(xiàng)目 -- plugin groupIdorg.codehaus.mojo/groupId artifactIdbuild-helper-maven-plugin/artifactId version3.3.0/version executions execution idattach-artifacts/id phasepackage/phase goals goalattach-artifact/goal /goals configuration artifacts !-- 為lib目錄下的每一個(gè)jar文件定義一個(gè)artifact -- artifact file${project.basedir}/lib/payment-gateway-sdk-2.1.0.jar/file typejar/type classifierpayment-gateway/classifier !-- 分類器避免沖突 -- /artifact artifact file${project.basedir}/lib/legacy-utils-1.0.0.jar/file typejar/type classifierlegacy-utils/classifier /artifact !-- 可以繼續(xù)添加更多 -- /artifacts /configuration /execution /executions /plugin /plugins /build /project關(guān)鍵點(diǎn)解析packagingpom/packaging這個(gè)模塊本身不產(chǎn)生代碼Jar它只是一個(gè)管理其他“附件”的容器。build-helper-maven-plugin它的attach-artifact目標(biāo)可以將任意文件“附加”為當(dāng)前Maven項(xiàng)目的一個(gè)產(chǎn)出物artifact。我們用它把lib/下的每個(gè)Jar都聲明為本模塊的一個(gè)附屬構(gòu)件。classifier分類器。因?yàn)閍rtifactId都是third-party-libs為了區(qū)分不同的Jar必須使用不同的分類器。這相當(dāng)于為每個(gè)Jar創(chuàng)建了一個(gè)唯一的坐標(biāo)com.yourcompany:third-party-libs:1.0.0:payment-gateway。步驟3在主pom.xml中引用并聚合首先將主項(xiàng)目的pom.xml修改為多模塊項(xiàng)目如果還不是的話project ... modelVersion4.0.0/modelVersion groupIdcom.yourcompany/groupId artifactIdyour-springboot-app/artifactId version1.0.0/version packagingpom/packaging !-- 主pom也改為pom -- modules modulethird-party-libs/module !-- 你的其他業(yè)務(wù)模塊 -- moduleyour-service-module/module /modules !-- 其他配置... -- /project然后在你的業(yè)務(wù)模塊如your-service-module的pom.xml中依賴這些外部Jardependency groupIdcom.yourcompany/groupId artifactIdthird-party-libs/artifactId version1.0.0/version classifierpayment-gateway/classifier typejar/type /dependency dependency groupIdcom.yourcompany/groupId artifactIdthird-party-libs/artifactId version1.0.0/version classifierlegacy-utils/classifier typejar/type /dependency步驟4構(gòu)建與打包在項(xiàng)目根目錄執(zhí)行mvn clean install這個(gè)命令會(huì)進(jìn)入third-party-libs模塊執(zhí)行install階段。build-helper-maven-plugin在package階段被觸發(fā)將lib/下的Jar文件作為附件安裝到本地Maven倉(cāng)庫(kù)。路徑類似于~/.m2/repository/com/yourcompany/third-party-libs/1.0.0/third-party-libs-1.0.0-payment-gateway.jar。然后構(gòu)建你的業(yè)務(wù)模塊此時(shí)Maven就能從本地倉(cāng)庫(kù)解析到這些依賴并將其打包進(jìn)Spring Boot的Fat Jar。實(shí)操心得這種方式的妙處在于mvn clean install成為了一個(gè)自包含的構(gòu)建指令。任何克隆了代碼庫(kù)的人只需要運(yùn)行這一條命令所有外部依賴就自動(dòng)“就位”了完全無需額外的手動(dòng)安裝步驟極大地提升了項(xiàng)目的可移植性和團(tuán)隊(duì)協(xié)作效率。4. Spring Boot打包插件深度配置無論采用上述哪種方案引入了依賴最終都要通過spring-boot-maven-plugin打包。理解它的工作機(jī)制能幫你更好地排查問題。4.1 插件默認(rèn)行為與“Fat Jar”結(jié)構(gòu)當(dāng)你執(zhí)行mvn package該插件會(huì)創(chuàng)建一個(gè)“可執(zhí)行的Jar”Fat Jar/Uber Jar。它的內(nèi)部結(jié)構(gòu)是這樣的your-app.jar ├── META-INF/ ├── BOOT-INF/ │ ├── classes/ # 你的應(yīng)用編譯后的.class文件 │ └── lib/ # **所有依賴的Jar包**包括從Maven倉(cāng)庫(kù)來的和外部引入的 └── org/springframework/boot/loader/ # Spring Boot的類加載器插件會(huì)收集所有scope為compile、runtime、provided默認(rèn)不打包但可通過配置改變的依賴并將它們解壓后的內(nèi)容或直接復(fù)制Jar放入BOOT-INF/lib/。關(guān)鍵在于它收集依賴的依據(jù)是Maven項(xiàng)目對(duì)象模型POM中解析到的依賴列表。4.2 關(guān)鍵配置項(xiàng)解析在pom.xml的插件配置中有幾個(gè)參數(shù)與依賴打包密切相關(guān)build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId configuration !-- 排除特定的依賴不打入Jar包 -- excludes exclude groupIdorg.projectlombok/groupId artifactIdlombok/artifactId /exclude /excludes !-- 包含特定的作用域依賴。默認(rèn)已包含compile, runtime想包含test則需顯式聲明 -- includeScoperuntime/includeScope !-- 使用classifier來構(gòu)建可執(zhí)行jar同時(shí)保留原始jar -- classifierexec/classifier /configuration /plugin /plugins /buildexcludes用于排除一些已聲明的依賴。例如Lombok只在編譯期需要運(yùn)行時(shí)不需要可以排除以減小包體積。includeScope控制打包時(shí)包含哪些作用域的依賴。默認(rèn)是runtime包含compile和runtime。如果你錯(cuò)誤地將外部依賴聲明為test或provided它就不會(huì)被打包。classifier設(shè)置分類器后會(huì)生成兩個(gè)Jaryour-app.jar原始的不可執(zhí)行和your-app-exec.jar可執(zhí)行的。這在某些部署場(chǎng)景下有用。一個(gè)常見誤區(qū)試圖通過配置resources來把lib/*.jar復(fù)制到BOOT-INF/lib/是行不通的。resources處理的是src/main/resources下的資源文件它們會(huì)被復(fù)制到BOOT-INF/classes/下而不是BOOT-INF/lib/。依賴Jar必須通過Maven的依賴機(jī)制引入。5. 疑難雜癥與排查實(shí)錄即使按照步驟操作依然可能遇到各種問題。下面是我在實(shí)踐中總結(jié)的常見“坑點(diǎn)”和排查思路。5.1 問題編譯成功但運(yùn)行時(shí)報(bào)ClassNotFoundException或NoClassDefFoundError這是最典型的問題意味著類在編譯時(shí)可見但在運(yùn)行時(shí)不可見。排查步驟確認(rèn)依賴是否在最終的Jar中# Linux/Mac jar tf target/your-application.jar | grep -i 部分jar名或類名 # 或直接查看lib目錄 jar tf target/your-application.jar | grep ^BOOT-INF/lib/如果在列表里找不到你的外部Jar說明打包環(huán)節(jié)出了問題。檢查依賴的作用域scope如果你用的是system作用域Spring Boot插件默認(rèn)是不打包system和provided作用域的依賴的。你需要顯式配置插件來包含它不推薦最好換方案configuration includeSystemScopetrue/includeSystemScope /configuration檢查是否被其他依賴排除使用mvn dependency:tree查看依賴樹確認(rèn)你的外部依賴沒有被exclusion標(biāo)簽排除。驗(yàn)證Jar文件本身用解壓工具打開外部Jar確認(rèn)你需要的.class文件確實(shí)在里面。有時(shí)下載的Jar可能損壞或不完整。5.2 問題在IDE如IntelliJ IDEA中運(yùn)行正常但mvn package后運(yùn)行失敗IDE特別是IntelliJ IDEA的構(gòu)建機(jī)制和Maven不完全一致。IDEA有時(shí)會(huì)將項(xiàng)目lib目錄下的Jar自動(dòng)添加到模塊的依賴路徑中但這并不代表Maven知道它們。解決方案永遠(yuǎn)以Maven的命令行構(gòu)建結(jié)果為準(zhǔn)。確保你的依賴引入方案方案一或四在命令行mvn clean compile下也能通過。可以在IDEA中打開Maven工具窗口執(zhí)行clean和compile命令來驗(yàn)證。5.3 問題多模塊項(xiàng)目中子模塊無法解析父模塊中管理的外部依賴在方案四中如果你在父pom的dependencyManagement里聲明了外部依賴子模塊需要顯式引用且必須帶上classifier和type。子模塊的依賴聲明必須和父模塊中定義的完全一致否則無法解析。5.4 問題使用system作用域時(shí)CI/CD流水線構(gòu)建失敗這是system作用域的硬傷。在Jenkins、GitLab CI等服務(wù)器上文件路徑完全不同。根本解決放棄system作用域采用方案一配合構(gòu)建腳本或方案四。方案四是最佳實(shí)踐它能保證環(huán)境的一致性。5.5 一個(gè)高級(jí)技巧處理“依賴的依賴”有時(shí)你引入的外部JarA.jar本身還依賴另一個(gè)外部JarB.jar。如果手動(dòng)安裝方案一你需要分別安裝A和B并在安裝A時(shí)通過-DpomFile指定其原始的POM如果存在這樣Maven才能知道A依賴B。如果只有Jar你可能需要手動(dòng)分析并安裝所有傳遞依賴或者將A和B一起打包成一個(gè)“超級(jí)Jar”使用maven-shade-plugin但后者可能引起類沖突。對(duì)于方案四你可以在third-party-libs模塊中為每個(gè)有依賴關(guān)系的Jar創(chuàng)建獨(dú)立的artifact配置并在dependencyManagement中聲明它們之間的依賴關(guān)系模擬一個(gè)微型的倉(cāng)庫(kù)。但這比較復(fù)雜通常更簡(jiǎn)單的做法是讓提供SDK的一方給出一個(gè)標(biāo)準(zhǔn)的Maven依賴坐標(biāo)或者至少提供一個(gè)包含所有必要Jar的“all-in-one”版本。6. 總結(jié)與最佳實(shí)踐建議經(jīng)過以上長(zhǎng)篇累牘的剖析我們可以提煉出處理Spring Boot打包外部Lib依賴的核心心法評(píng)估優(yōu)先首先明確這個(gè)外部依賴是編譯時(shí)需要還是僅運(yùn)行時(shí)需要。這決定了你能選擇哪些方案。團(tuán)隊(duì)協(xié)作與自動(dòng)化優(yōu)先如果是團(tuán)隊(duì)項(xiàng)目或需要CI/CD方案四自定義模塊是首選。它犧牲了一點(diǎn)前期配置復(fù)雜度換來了長(zhǎng)期的構(gòu)建穩(wěn)定性和團(tuán)隊(duì)協(xié)作便利性。慎用system作用域除非是絕對(duì)一次性、個(gè)人使用的簡(jiǎn)單項(xiàng)目否則盡量避免。它的可移植性問題遲早會(huì)暴露。文檔化無論采用哪種方案一定要在項(xiàng)目的README.md或CONTRIBUTING.md中清晰寫明對(duì)外部依賴的處理方式。如果是手動(dòng)安裝給出確切的命令如果是自定義模塊說明構(gòu)建順序。統(tǒng)一入口盡量將所有的外部Jar集中管理在一個(gè)目錄如/third-party-libs即使采用手動(dòng)安裝也建議寫一個(gè)安裝腳本遍歷該目錄下的所有Jar進(jìn)行安裝。終極方案長(zhǎng)遠(yuǎn)來看推動(dòng)將這些外部Jar部署到公司內(nèi)部的Maven私有倉(cāng)庫(kù)如Nexus、Artifactory。這是最規(guī)范、最一勞永逸的解決方案。方案四實(shí)際上是為最終遷入私有倉(cāng)庫(kù)做好了準(zhǔn)備你只需要將maven-install-plugin換成maven-deploy-plugin即可。最后記住Maven哲學(xué)的核心是“約定大于配置”。當(dāng)遇到“非約定”的外部Jar時(shí)我們的目標(biāo)不是對(duì)抗這個(gè)哲學(xué)而是通過規(guī)范化的手段安裝到倉(cāng)庫(kù)、創(chuàng)建模塊將這些“例外”重新納入到“約定”的體系中來管理。這樣你的Spring Boot項(xiàng)目才能在各種環(huán)境下穩(wěn)定、可靠地構(gòu)建和運(yùn)行。