一文理解Maven如何解決依賴沖突與循環(huán)依賴
Maven中依賴沖突與循環(huán)依賴是開發(fā)過程中比較令人頭疼的問題。
依賴沖突
首先介紹下Maven中依賴管理的策略。
依賴傳遞:如果A依賴B,B依賴C,那么引入A,意味著B和C都會被引入。
最近依賴策略:如果一個項目依賴相同的groupId、artifactId的多個版本,那么在依賴樹(mvn dependency:tree)中離項目最近的那個版本將會被使用。
具體如下:
從當前項目出發(fā),對于同一依賴,優(yōu)先使用路徑最短的那個,無論版本號高低。

同級別的引用,若pom.xml直接引用了兩個不同版本的同一個依賴,maven會使用后解析的依賴版本。

若兩個不同版本的同一依賴都不是直接在pom.xml下引入,而是間接引入。那么哪個依賴先被引用,就使用哪個版本。

解決依賴沖突
使用
<dependencyManagement>用于子模塊的版本一致性,可以在parent工程里統(tǒng)一管理所有工程的依賴版本。使用
<exclusions>去除多余的依賴,IDEA提供相關(guān)可視化的操作。根據(jù)最近依賴策略使用
<dependency>,直接在當前項目中指定依賴版本。
實際開發(fā)中依賴沖突的問題復(fù)雜多變,需要具體問題具體處理。除了上面三種解決方法,工程結(jié)構(gòu)調(diào)整也是一個可能的選擇。
循環(huán)依賴
正常情況下,循環(huán)依賴是很少見的,當很多個項目互相引用的時候,就可能出現(xiàn)循環(huán)依賴,一般根據(jù)錯誤信息就能解決循環(huán)依賴。
解決循環(huán)依賴
使用
build-helper-maven-plugin插件可以解決無法構(gòu)建的問題,但是只是一個規(guī)避措施,工程的依賴關(guān)系依然是混亂的。
比如A依賴B,B依賴C,C依賴A的情況。這個插件提供了一種規(guī)避措施,即臨時地將工程A、B、C合并成一個中間工程,編譯出臨時的模塊D。然后A、B、C再分別依賴臨時模塊D進行編譯。
通過重構(gòu),從根本上消除循環(huán)依賴。
如果循環(huán)依賴中確實有多余的部分,可以使用
<exclusions>去除多余的依賴。(IDEA可以通過圖像化界面定位循環(huán)依賴)
補充
Maven的基礎(chǔ)知識
groupId是項目組織唯一的標識符,實際對應(yīng)JAVA的包的結(jié)構(gòu),是main目錄里java的目錄結(jié)構(gòu)。
一般分為多個段,第一段為域,第二段為公司名稱…域又分為org、com、cn等等許多,其中org為非營利組織,com為商業(yè)組織。
artifactId是項目的唯一的標識符,實際對應(yīng)項目的名稱,就是項目根目錄的名稱。
一個Maven項目,同一個groupId同一個artifactId下,只會加載一個version。
例如:
<dependency>
<groupId>org.xiaohui</groupId>
<artifactId>maven-desc</artifactId>
<version>5.3.8</version>
</dependency>
依照這個設(shè)置,包結(jié)構(gòu)最好是org.xiaohui.maven-desc。如果有個StudentDao,那全路徑就是org.xiaohui.maven-desc.dao.StudentDao。
Maven倉庫有哪些

本地倉庫
本地倉庫指的是${user_home}/.m2/repository/,Maven默認會先從本地倉庫內(nèi)尋找所需Jar包。如果本地倉庫不存在,Maven才會向遠程倉庫請求下載,同時緩存到本地倉庫。遠程倉庫分為中央倉庫,私服和其他公共庫。
中央倉庫
Maven自帶的遠程倉庫,不需要特殊配置。如果私服上也不存在Maven所需 Jar包,那么就去中央倉庫上下載Jar包,同時緩存在私服和本地倉庫。私服
為了節(jié)省資源,一般是局域網(wǎng)內(nèi)設(shè)置的私有服務(wù)器,當本地倉庫內(nèi)不存在Maven 所需Jar包時,會先去私服上下載Jar包。(內(nèi)網(wǎng)速度要大于從外部倉庫拉取鏡像的速度)其他公共庫
為了解決中央倉庫網(wǎng)絡(luò)對于國內(nèi)不穩(wěn)定的問題,常用如阿里云鏡像倉庫。
Maven的打包命令
IDEA中的Maven插件功能如圖:

這個圖表示Maven逐次遞進(執(zhí)行下面的命令就會包含上面的)的打包命令。
常用的打包命令:
clean:清理本地工程Jar包。
package:本地工程打成Jar包。會執(zhí)行clean和compile。
install:將本地工程Jar上傳到本地倉庫。
deploy:上傳到遠程倉庫。
Maven的依賴范圍(scope)
代碼有編譯、測試、運行的過程,顯然有些依賴只用于測試,比如Junit;有些依賴編譯用不到,只有運行的時候才能用到,比如MySQL的驅(qū)動包在編譯期就用不到(編譯期用的是JDBC接口),而是在運行時用到的;還有些依賴,編譯期要用到,而運行期不需要提供,因為有些容器已經(jīng)提供了,比如servlet-api在tomcat中已經(jīng)提供了,只需要的是編譯期提供而已。
所以Maven支持指定依賴的scope:
compile:默認的scope,運行期有效,需要打入包中。
provided:編譯期有效,運行期不需要提供,不會打入包中。
runtime:編譯不需要,在運行期有效,需要導(dǎo)入包中。(接口與實現(xiàn)分離)
test:測試需要,不會打入包中。
