Maven依賴沖突的產生原因和解決方式


ref:https://blog.csdn.net/qq_27529917/article/details/79741607

http://www.yangbing.club/2017/07/15/solution-for-jar-conflicts/

先來看下Maven的仲裁機制:

  • 優先按照依賴管理<dependencyManagement>元素中指定的版本聲明進行仲裁,此時下面的兩個原則都無效了
  • 若無版本聲明,則按照“短路徑優先”的原則(Maven2.0)進行仲裁,即選擇依賴樹中路徑最短的版本
  • 若路徑長度一致,則按照“第一聲明優先”的原則進行仲裁,即選擇POM中最先聲明的版本

 

現在我們了解了classloader的結構和工作原理,那么我們如何實現jar包的容器隔離呢?

答案很簡單: 我們實現一個新的classloader就可以了!

 

自定義ClassLoader

在自定義ClassLoader的子類時候,我們常見的會有兩種做法,一種是重寫loadClass方法,另一種是重寫findClass方法。其實這兩種方法本質上差不多,畢竟loadClass也會調用findClass,但是從邏輯上講我們最好不要直接修改loadClass的內部邏輯。
個人認為比較好的做法其實是只在findClass里重寫自定義類的加載方法。
為啥說這種比較好呢,因為前面我也說道,loadClass這個方法是實現雙親委托模型邏輯的地方,擅自修改這個方法會導致模型被破壞,容易造成問題。因此我們最好是在雙親委托模型框架內進行小范圍的改動,不破壞原有的穩定結構。同時,也避免了自己重寫loadClass方法的過程中必須寫雙親委托的重復代碼,從代碼的復用性來看,不直接修改這個方法始終是比較好的選擇。
當然,如果是刻意要破壞雙親委托模型就另說。

破壞雙親委托模型

為什么要破壞雙親委托模型呢?
其實在某些情況下,我們可能需要加載兩個不同的類,但是不巧的是這兩個類的名字完全一樣,這時候雙親委托模型就無法滿足我們的要求了,我們就要重寫loadClass方法破壞雙親委托模型,讓同一個類名加載多次。當然,這里說的破壞只是局部意義上的破壞。
但是類名相同了,jvm怎么區別這兩個類呢?顯然,這並不會造成什么世界觀的崩塌,其實類在jvm里並不僅是通過類名來限定的,他還屬於加載他的ClassLoader。由不同ClassLoader加載的類其實是互不影響的。

有沒有不用反射的更優雅的調用方法

顯然,每次都用反射來調用還是太蠢了,難道就沒有更方便的類似用類名引用的方法么?當然是有的,前面之所以不能直接用類名引用是因為原生類的類加載器是systemClassLoader,而從class文件創建的類的類加載器是自定義的classLoader,這兩個類本質不一樣,因此才不能互相強制轉換,如果硬要強制轉換就會報ClassCastException。那么,如果我們提取一個父類,父類由systemClassLoader加載,而子類由自定義classLoader加載,然后強制轉換的時候轉換成父類不就好了么?
做個試驗,創建一個父類Father,其實就是提取了個抽象方法:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM