一文詳解Maven中依賴沖突的正確處理方法
事情是這樣的
前幾天遇到一個(gè)線上問(wèn)題,SQL 解析直接超時(shí)了,日志里一堆 JSQLParserException: Time out occurred。排查下來(lái)發(fā)現(xiàn)是 JSqlParser 4.6 版本的一個(gè)已知 bug,解析復(fù)雜 SQL 的時(shí)候會(huì)陷入回溯地獄,CPU 直接打滿。
解決方案很簡(jiǎn)單,升級(jí)到 4.9 就好了。但問(wèn)題來(lái)了——我們項(xiàng)目里有好幾個(gè)庫(kù)都依賴 JSqlParser:
- mybatis-plus-core 依賴 4.6
- pagehelper 依賴 4.6
- 我們自己的 flcloud-jdbc-cipher 要用 4.9
這就尷尬了,同一個(gè) jar 包,三個(gè)地方要三個(gè)版本,Maven 怎么處理?
Maven 的依賴仲裁機(jī)制
先說(shuō)結(jié)論:Maven 不會(huì)真的引入多個(gè)版本,最終只會(huì)保留一個(gè)。
那它怎么決定保留哪個(gè)?規(guī)則其實(shí)挺簡(jiǎn)單的:

舉個(gè)例子,假設(shè)依賴樹(shù)是這樣的:

三個(gè) jsqlparser,深度分別是 4 層、3 層、2 層。按"路徑最短優(yōu)先",4.9 勝出。
但實(shí)際情況往往沒(méi)這么簡(jiǎn)單,深度可能差不多,這時(shí)候就看誰(shuí)在 pom 里寫(xiě)在前面了。
我當(dāng)時(shí)的第一反應(yīng):到處寫(xiě) exclusion
說(shuō)實(shí)話,我一開(kāi)始的想法就是簡(jiǎn)單粗暴,把不想要的版本排除掉:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
<exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>2.1.0</version>
<exclusions>
<exclusion>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</exclusion>
</exclusions>
</dependency>
能用是能用,但問(wèn)題也很明顯:
- 要改好幾個(gè)地方,容易漏
- 新同事不知道這段歷史,可能哪天又加了個(gè)依賴把 4.6 帶進(jìn)來(lái)
- 看著就難受,到處都是 exclusion
后來(lái)發(fā)現(xiàn)更優(yōu)雅的方式
其實(shí) Maven 早就提供了統(tǒng)一管理依賴版本的機(jī)制:在父 pom 的 dependencyManagement 里鎖版本。
<!-- 父 pom.xml -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.9</version>
</dependency>
</dependencies>
</dependencyManagement>
就這么簡(jiǎn)單。加上這段之后,不管子模塊的依賴樹(shù)里 jsqlparser 出現(xiàn)多少次、原本寫(xiě)的是什么版本,最終都會(huì)被統(tǒng)一成 4.9。

改完之后跑一下 mvn dependency:tree | grep jsqlparser,確認(rèn)只剩一個(gè)版本就行了。
為什么 dependencyManagement 優(yōu)先級(jí)最高
這塊我之前也沒(méi)太搞明白,后來(lái)翻了下 Maven 的文檔,大概是這么個(gè)優(yōu)先級(jí)順序:

dependencyManagement 的作用就是"預(yù)定義"版本號(hào),它不會(huì)真的引入依賴,但一旦這個(gè)依賴在依賴樹(shù)中出現(xiàn),就會(huì)強(qiáng)制使用預(yù)定義的版本。
所以它的優(yōu)先級(jí)比什么路徑深度、聲明順序都高,直接一錘定音。
幾個(gè)要注意的地方
驗(yàn)證是必須的
改完版本之后,別急著提交,先驗(yàn)證一下各個(gè)庫(kù)在新版本下能不能正常工作。jsqlparser 4.7 之后有些 API 變了,比如 SubSelect、SelectBody 這些類被 干掉了。如果哪個(gè)庫(kù)用到了這些老 API,啟動(dòng)的時(shí)候就會(huì)報(bào) NoSuchMethodError。
我們這次還好,mybatis-plus 和 pagehelper 用的都是比較基礎(chǔ)的 API,升到 4.9 之后跑了下單測(cè),沒(méi)啥問(wèn)題。
查看依賴樹(shù)的命令
# 看完整依賴樹(shù) mvn dependency:tree # 只看某個(gè)依賴 mvn dependency:tree | grep jsqlparser # 更詳細(xì)的沖突分析 mvn dependency:tree -Dverbose -Dincludes=com.github.jsqlparser:jsqlparser
IDEA 也能看
如果你用 IDEA,pom 文件底部有個(gè) "Dependency Analyzer" 標(biāo)簽頁(yè),能看到依賴樹(shù)和沖突情況,比命令行直觀多了。
總結(jié)一下

說(shuō)白了就是:能用 dependencyManagement 解決的,就別到處寫(xiě) exclusion。
前者是"我說(shuō)了算",后者是"我不要這個(gè)不要那個(gè)"。心態(tài)都不一樣。
到此這篇關(guān)于一文詳解Maven中依賴沖突的正確處理方法的文章就介紹到這了,更多相關(guān)Maven依賴沖突內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)字符串轉(zhuǎn)String數(shù)組的方法示例
這篇文章主要介紹了java實(shí)現(xiàn)字符串轉(zhuǎn)String數(shù)組的方法,涉及java字符串的遍歷、分割、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(10)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07
Java虛擬機(jī)JVM類加載機(jī)制(從類文件到虛擬機(jī))
所謂的類加載機(jī)制就是虛擬機(jī)將class文件加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行驗(yàn)證,轉(zhuǎn)換解析和初始化,形成虛擬機(jī)可以直接使用的java類型,本文給大家介紹類加載機(jī)制過(guò)程從類文件到虛擬機(jī)的詳細(xì)說(shuō)明,感興趣的朋友跟隨小編一起看看吧2021-06-06
解決ApplicationContext獲取不到Bean的問(wèn)題
這篇文章主要介紹了解決ApplicationContext獲取不到Bean的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
Java ffmpeg 實(shí)現(xiàn)視頻加文字/圖片水印功能(示例代碼)
本文介紹了使用Java和ffmpeg庫(kù)實(shí)現(xiàn)視頻加文字或圖片水印的方法,通過(guò)引入依賴代碼和示例,詳細(xì)說(shuō)明了如何將文字水印和圖片水印添加到視頻中,為需要在視頻中加入水印的開(kāi)發(fā)者提供了實(shí)用的指導(dǎo),這種方法不僅增強(qiáng)了視頻內(nèi)容的版權(quán)保護(hù),也為視頻編輯提供了更多的可能性2024-10-10
SpringCloud2020整合Nacos-Bootstrap配置不生效的解決
這篇文章主要介紹了SpringCloud2020整合Nacos-Bootstrap配置不生效的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
springboot打包JAR包瘦身lib和配置文件分離方式
本文介紹了如何通過(guò)優(yōu)化POM.xml配置來(lái)減小JAR包大小,提高傳輸速度,主要步驟包括:指定打包環(huán)境和跳過(guò)編譯單元測(cè)試、JAR打包排除配置文件和lib、提供全量包便于開(kāi)發(fā)環(huán)境使用、將lib和配置文件單獨(dú)復(fù)制出來(lái)2024-11-11

