日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

程序员需要了解依赖冲突的原因以及解决办法

發布時間:2025/3/16 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员需要了解依赖冲突的原因以及解决办法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

依賴沖突是日常開發中經常碰到的過程,如果運氣好,并不會有什么問題。偏偏阿粉有點背,碰到好幾次生產問題,排查一整晚,最后發現卻是依賴沖突的引起的問題。

沒碰到過這個問題同學可能沒什么感覺,阿粉舉兩個最近碰到例子,讓大家感受一些。

例子 1:

我們公司有個古老的業務基礎包 A。B,C 業務依賴這個包。某個團隊拷貝 A 的部分代碼進行重構,類名與路徑完全一樣,然后重新打包成 D 發布。

一次業務改動,B 業務也引入了 D 包,測試環境運行的時候,一切 OK,但是在生產運行時,卻拋出?NoSuchMethodError。

問題原因在于 B 業務依賴 A,D。而 A,D 存在兩個同包同名類,運行的時候,具體加載誰,不同環境還真不一樣。

例子 2:

A 業務使用?Dubbo?進行?RPC調用,?Dubbo?需要依賴?javassist。當前依賴關系為:

A------->Dubbo------->javassist-3.18.1.GA

某次改動中引入另外一個第三方開源包,其依賴?javassist-3.15.0-GA?。生產發布的時候,將?javassist-3.15.0-GA?打包到應用中,由于生產環節為 JDK1.8,從而導致運行直接失敗。

除了上述問題,依賴沖突還可能導致應用拋出?ClassNotFoundException,NoClassDefFoundError?等錯誤。

拋出錯誤這種情況還算好,還比較容易定位問題。怕就怕,不同版本同一個類內部邏輯不同,從而導致業務異常。這種問題,真的很讓人抓狂,讓人頭禿。

仔細分析依賴沖突,主要可以分為兩類:

  • 項目同一依賴應用,存在多版本,每個版本同一個類,可能存在差異。

  • 項目不同依賴應用,存在包名,類名完全一樣的類。

下面我們分析一下依賴沖突產生的原因。


依賴沖突原因

1.1 依賴機制

Maven?依賴分為兩種情況,直接依賴與間接依賴,這個比較好理解,大家直接看圖就好。

1.2 仲裁機制

如果 A 應用間接依賴多個 C 應用,且版本都不一樣,Maven 將會通過仲裁機制選擇:

  • 優先按照依賴管理元素中指定的版本聲明進行仲裁時,下面的兩個原則都無效了

  • 短路徑優先

  • 若路徑相同,將看 pom 中聲明的順序。

第一條原則,我們下面再說。

第二條原則,如下圖:

A 間接依賴兩個版本 E,這種情況下,由于 A 到 E-1.0 路徑最短,所以 A 中將會使用 E-1.0。

如果路徑恰好一樣,那么這種情況下?Maven?只能根據?pom?中的順序,選擇最先聲明的,這也是個無奈的選擇。

1.3 scope 屬性

Maven 項目可以分為三個階段:編譯階段,測試階段,運行階段了。通過?scope?屬性,我們可以決定依賴應用是否參與以上階段,也將會影響依賴傳遞。

Maven?提供 6 種?scope?:

  • compile

  • provided

  • runtime

  • test

  • system

  • import

compile

compile?是?Maven?默認屬性,將會使依賴包參與項目的編譯,測試,運行階段。當然,項目打包之后將會包含該依賴。

provided

provided?意味著依賴僅參與項目編譯,測試的階段。若有如下依賴關系:

A----->B----->C

C 的?scope?為provided,C 將會參與 B 的編譯,測試階段,但是 C 不會傳遞給 A。如果 A 運行過程需要 C,需要自己直接引入 C 依賴。典型如?Servlet API,因為?Tomcat?等容器內部會提供。

runtime

runtime?代表依賴不再參與項目編譯階段,只參與測試,運行階段。

若依賴不參與編譯階段,這種情況 IDE 中是無法導入相應的類的。若存在依賴類,編譯過程中將會報錯。

典型的例子是?JDBC?驅動包,如?mysql?:

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> <scope>runtime</scope></dependency>

知識點:這個好處在于,只能使用 JDBC 標準接口,這樣就不會與特定的數據庫綁定。后續若切換數據庫,只需要更換 pom,然后修改相應的參數即可。

test

test?僅參與測試階段的工作,典型的例子為?junit:

<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope></dependency>

system

system?與?provided?范圍一致,只不過?system?需要使用?systemPath?屬性指定本地路徑,而?provided?將會從?Maven?倉庫拉取。

import

import?比較特殊,不會參與以上階段運行。其只能在?dependencyManagement下使用,且?type需要為?pom。典型的例子為 Spring-boot 依賴。

<dependencyManagement> <dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>

知識點:通過這種方式,解決單繼承問題,也可以更好將依賴分類。

另外?Maven scope?將會影響依賴傳遞。

如果依賴關系為:?A--->B--->C,A 依賴 B,B 依賴 C。最左列代表 B 的?scope?屬性,第一行代表 C 的?scope?屬性

如上所示,當 C 的?scope?為?provided/test, C 只在 B 中起作用,不會通過間接依賴傳遞給 A。

當且僅當 B 的?scope?為?compile,且 C?scope?為?runtime?,A 將會間接依賴 C,且?scope?為?runtime。其他情況下,C 的 scope 將會與 B 的 scope 一致。

?

解決沖突的方法

2.1 使用 Maven 屬性控制依賴傳遞

依賴沖突時,根據錯誤日志,定位到沖突類,定位相應?jar?包,最后通過?excludes?排除相應的包。

另外可以結合?IDEA Maven Helper?插件,主動檢查沖突依賴,提前排除。

通過插件,我們可以清晰看到沖突包,以及依賴路徑,還有相應的?Scope。

除了排除依賴,我們可以通過合理的設置?scope?屬性,不讓依賴傳播下去。比如說,A 需要是使用?Spring-beans?包中某些類。如果其他項目鐵定會使用 Spring,那么我們可以將 A 中?Spring-beansscope?設置為?provided,讓其他項目自己選擇引入?Spring-beans?的版本。

這個適合公共基礎包,其他包不要隨便使用provided,若使用一定要寫清楚,使用過程中需要引入的依賴。

以上方法雖然治標,但是不治本。如果想依賴沖突不發生,我們需要提前建立一定的規范,團隊一起遵守,才能有效避免該類問題。

  • 應用項目中使用?dependencyManagement統一管理基礎依賴,定義統一的版本,如常用中間包,工具包,日志包。

  • 二方包中不要引入無關的依賴,做到盡量少的依賴。團隊開發中,比較常見情況是二方包繼承公共的父 pom,從而導致繼承許多無相關的依賴,這種情況可以單獨管理。

  • 二方包做好向下兼容,不要隨意改動現有類名,方法名,字段名。

  • 項目應用上線之前,將?snapshot?替換成正式版本。雖然?snapshot?修改起來很方便,但是正因為這個特性,可以被隨便修改。如果某次生產打包發布不注意,就會引入。

  • 二方包不要使用同一個包名,類名。一般來說,團隊開發中,包名,類名一樣概率比較小。這種比較容易出現在一些重構項目,復制原來類,重構打包發布。對于情況下可以修改包名。如?cmomon-lang3?是?common-lang?升級版,?cmomon-lang3包名為 org.apache.commons.lang3,而?common-lang?包名為?org.apache.commons.lang


  • 總結

    如果我們把?NPE?問題當做新手村普通怪物,那么依賴沖突問題就是人馬這種精英怪。剛開始遇到,我們會被虐的比較慘。只有我們不斷升級,學習掌握技巧,然后才能可以從容不迫解決。

    ps:塞爾達中,你們第一次遇見人馬,打了幾次?阿粉記得那天整整從晚上九點打到凌晨兩點,就是打不過啊~


    幫助文檔

    Maven Dependency Scopes

    Maven optional關鍵字透徹圖解

    有道無術,術可成;有術無道,止于術

    歡迎大家關注Java之道公眾號

    好文章,我在看??

    總結

    以上是生活随笔為你收集整理的程序员需要了解依赖冲突的原因以及解决办法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。