Maven直接依賴、間接依賴、依賴沖突、依賴仲裁的實(shí)現(xiàn)
直接依賴和間接依賴
在項(xiàng)目中直接引入的依賴叫做直接依賴,而那些被動(dòng)引入的就叫間接依賴
比如上圖中,A 是我們的項(xiàng)目,我們在項(xiàng)目中直接引入了 B 模塊,所以 B 和 A 的關(guān)系就是直接依賴,而 B 工程內(nèi)部引入了 C,所以 B 和 C 也是直接依賴關(guān)系,如果 B 工程在引入 C 時(shí),指定了 C 模塊的依賴范圍是 <scope>compile</scope>
,那么 C 模塊就會(huì)隨著 B 模塊一同被引入到我們的工程A 中,這時(shí)候 A 和 C 的關(guān)系就是間接依賴
依賴沖突
Maven 的依賴沖突,我認(rèn)為有兩種情況,Maven 能自動(dòng)解決的、需要手動(dòng)解決的
1. Maven 可以自動(dòng)解決的依賴沖突
在項(xiàng)目中,不管是直接依賴還是間接依賴,當(dāng)有多個(gè) <groupId>
、 <artifactId>
相同, <version>
不同的依賴引入時(shí),Maven 就會(huì)認(rèn)為我們引入了相同模塊的不同版本,其就會(huì)被判定為依賴沖突,這種情況 Maven 會(huì)用自己的仲裁機(jī)制幫我們?nèi)∩?/p>
2. 需要手動(dòng)解決的依賴沖突
模塊間的 <groupId>
、 <artifactId>
、 <version>
都不相同,但是引入的這些模塊中具有相同路徑的類(包名+類名完全相同),這個(gè)時(shí)候就需要我們自己去解決依賴沖突問題
Maven 的依賴仲裁
依賴仲裁是 Maven 自動(dòng)解決依賴沖突的手段,我們想更好的利用它,就必須知道其仲裁的規(guī)則,其通過 最短路徑優(yōu)先
和 先聲明優(yōu)先
兩個(gè)依據(jù)來判斷最終留下的模塊
最短路徑優(yōu)先
當(dāng)項(xiàng)目的依賴樹中存在相同模塊的不同版本時(shí),Maven 的仲裁機(jī)制就會(huì)介入,其首先會(huì)通過最短路徑的方式來對沖突的模塊進(jìn)行取舍,如下圖,假設(shè)我們的項(xiàng)目是A,明顯C模塊發(fā)生了依賴沖突,那么按照最短路徑優(yōu)先的原則,Maven 最后會(huì)留下 A → B → C 1.0 這個(gè)路徑下的 C 模塊
先聲明優(yōu)先
當(dāng)兩個(gè)依賴沖突的模塊,其路徑距離相同時(shí),就會(huì)使用先聲明優(yōu)先的規(guī)則,這個(gè)就很簡單了,就是留下先聲明的模塊,如下圖,假設(shè)我們的項(xiàng)目是A,兩個(gè)沖突的模塊C到 A 的距離是相同的,這時(shí) Maven 就會(huì)根據(jù)先聲明優(yōu)先的規(guī)則選擇A → B → C 1.0 這個(gè)路徑下的 C 模塊,因?yàn)槠渎暶髟谇?/p>
至于什么叫先聲明,非常簡單,用上圖例子,我寫個(gè)偽代碼
<!-- 這個(gè) B 的依賴信息就是先聲明的,所以仲裁后會(huì)留下B模塊中依賴的C模塊 --> <dependency> <groupId>B</groupId> <artifactId>B</artifactId> <version>release</version> </dependency> <dependency> <groupId>D</groupId> <artifactId>D</artifactId> <version>release</version> </dependency>
了解仲裁規(guī)則后,也可以利用 Maven 的仲裁規(guī)則,保留自己想要的模塊,比如上面例子中,我們想保留模塊 C 2.0,那么就可以將模塊 C 2.0 的依賴信息主動(dòng)聲明在依賴列表的最前面,這樣不論是最短路徑規(guī)則還是先聲明的規(guī)則,都會(huì)判定 C 2.0 被保留,偽代碼如下:
<!--在依賴列表的最前面主動(dòng)聲明模塊C2.0的依賴信息--> <dependency> <groupId>C</groupId> <artifactId>C</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>B</groupId> <artifactId>B</artifactId> <version>release</version> </dependency> <dependency> <groupId>D</groupId> <artifactId>D</artifactId> <version>release</version> </dependency>
手動(dòng)解決依賴沖突
需要手動(dòng)解決的情況,是指不同模塊中,具有相同路徑的類(包名和類名完全相同),從而導(dǎo)致項(xiàng)目啟動(dòng)后,類加載器加載了同名的非目標(biāo)類,從而出現(xiàn) ClassNotFoundException
、 NoClassDefFoundError
、 LinkageError
等類似的錯(cuò)誤
手動(dòng)解決依賴沖突,首先需要找出路徑相同的類所在的模塊,其次決定要留用的模塊
找出類路徑相同的模塊
可以借助 Maven 的生命周期插件 maven-enforcer-plugin
1. 在項(xiàng)目的 Pom.xml 中添加配置
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.4.1</version> <executions> <execution> <id>enforce-dependencies</id> <phase>validate</phase> <goals> <goal>display-info</goal> <goal>enforce</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.codehaus.mojo</groupId> <artifactId>extra-enforcer-rules</artifactId> <version>1.0-beta-4</version> </dependency> </dependencies> <configuration> <rules> <banDuplicateClasses> <findAllDuplicates>true</findAllDuplicates> </banDuplicateClasses> </rules> </configuration> </plugin> </plugins> </build>
(2) 執(zhí)行 mvn clean package enforcer:enforce
命令后,就能看見重復(fù)的類和模塊
(3) 找到?jīng)_突的模塊后,刪掉棄用的模塊,如果是直接依賴的模塊直接刪除依賴信息就好,如果是間接依賴的模塊,就要使用 <exclusions>
排除依賴傳遞,方式如下:
<dependency> <groupId></groupId> <artifactId></artifactId> <version></version> <!-- 排除依賴傳遞 --> <exclusions> <exclusion> <groupId>要棄用的模塊的groupId</groupId> <artifactId>要棄用的模塊的artifactId</artifactId> </exclusion> </exclusions> </dependency>
到此這篇關(guān)于Maven直接依賴、間接依賴、依賴沖突、依賴仲裁的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Maven直接依賴、間接依賴、依賴沖突、依賴仲裁內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot集成FastDFS實(shí)現(xiàn)防盜鏈功能
FastDFS是一個(gè)高性能的分布式?件系統(tǒng),本文將為大家詳細(xì)介紹一下SpringBoot如何集成FastDFS實(shí)現(xiàn)防盜鏈功能,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04解決?IDEA?Maven?項(xiàng)目中"Could?not?find?artifact"?
這篇文章主要介紹了解決IDEA Maven項(xiàng)目中Could not?find?artifact問題的常見情況和解決方案,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07spring整合redis以及使用RedisTemplate的方法
本篇文章主要介紹了spring整合redis以及使用RedisTemplate的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05利用Java實(shí)現(xiàn)word導(dǎo)入導(dǎo)出富文本(含圖片)的詳細(xì)代碼
這篇文章主要為大家詳細(xì)介紹了利用Java實(shí)現(xiàn)word導(dǎo)入導(dǎo)出富文本(含圖片),文中的示例代碼講解詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,感興趣的小伙伴可以學(xué)習(xí)一下2024-02-02Java設(shè)計(jì)模式之原型模式詳細(xì)解析
這篇文章主要介紹了Java設(shè)計(jì)模式之原型模式詳細(xì)解析,原型模式就是用一個(gè)已經(jīng)創(chuàng)建的實(shí)例作為原型,通過復(fù)制該原型對象來創(chuàng)建一個(gè)和原型對象相同的新對象,需要的朋友可以參考下2023-11-11MyBatis如何使用PageHelper實(shí)現(xiàn)分頁查詢
這篇文章主要介紹了MyBatis如何使用PageHelper實(shí)現(xiàn)分頁查詢,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Mybatis聯(lián)合查詢的實(shí)現(xiàn)方法
本文主要介紹了 Mybatis聯(lián)合查詢的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01SpringBoot隨機(jī)端口啟動(dòng)的實(shí)現(xiàn)
本文主要介紹了SpringBoot隨機(jī)端口啟動(dòng)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07Spring Boot中使用Actuator的/info端點(diǎn)輸出Git版本信息
這篇文章主要介紹了Spring Boot中使用Actuator的/info端點(diǎn)輸出Git版本信息,需要的朋友可以參考下2017-06-06