在比較大型的專案中使用 Maven,有頗高的機率會遇到版本衝突的問題
例如 project A 使用了 guava 的某個 15 版才開始有的功能,而 project B 則是引用了 guava v14
接著有一個新的專案 project C,必須要同時引用 project A 和 project B,這時會發生什麼事呢?
有可能會造成最後打包出來的專案,裡面實際上被打包的是 guava v14
因而導致了在執行時,執行到 project A 的程式碼,就遇到 class/method not found 之類的錯誤訊息。
在 Maven 中,針對這個問題有一些基礎的解法 [1]
當同樣的套件被重複引用時,Maven 的基礎規則是誰先寫就看誰
但畢竟在遇到某些動態載入之類的情境時,並不是那麼容易可以決定誰先寫
更何況遇到的如果是 guava 這種被大量引用的函式庫,其實我們不見得能夠清楚地知道到底有哪些函式庫用了它。
因此,在基礎的解法之上的下個階段,就是利用 dependencyManagement 來指派版本了。
具體來說,dependencyManagement 的指派好像有兩種用法,一種是建立父子關係,另一種則是 BOM
詳細的範例其實都可以參考官方文件 [1],這裡紀錄的是 BOM。
首先,假設我想要確保 guava 使用的版本是 v19.0,我可以先建立一個 BOM 專案,這個專案的 pom 檔內容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" < modelVersion >4.0.0</ modelVersion > < groupId >com.example</ groupId > < artifactId >bom</ artifactId > < version >1.0</ version > < packaging >pom</ packaging > < name >bom</ name > < dependencyManagement > < dependencies > < dependency > < groupId >com.google.guava</ groupId > < artifactId >guava</ artifactId > < version >19.0</ version > </ dependency > </ dependencies > </ dependencyManagement > </ project > |
這裡需要特別注意的地方,大概是第 8 行的 packaging 必須是 pom
而 dependencyManagement 內,就寫上所有要預先指定版本的套件,這裡只寫了 guava v19。
接著,當我要使用的時候,也是以 dependencyManagement 的標籤來引用上面寫好的 com.example.bom 這個套件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
< project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" < modelVersion >4.0.0</ modelVersion > < groupId >com.example</ groupId > < artifactId >project</ artifactId > < version >1.0</ version > < packaging >jar</ packaging > < name >project-a</ name > < dependencyManagement > < dependencies > < dependency > < groupId >com.example</ groupId > < artifactId >bom</ artifactId > < version >1.0</ version > < type >pom</ type > < scope >import</ scope > </ dependency > </ dependencies > </ dependencyManagement > < dependencies > < dependency > < groupId >com.google.guava</ groupId > < artifactId >guava</ artifactId > </ dependency > </ dependencies > </ project > |
在這裡可以注意到兩個部份,一個是 com.example.bom 是以 pom type 被宣告在 dependencyManagement 中
另外,引用 guava 時,並沒有宣告 guava 的版本
這是因為 guava 的版本已經在 com.example.bom 裡被定義了,因此就算在這裡宣告了,也會被編譯器識別為不需要的內容。
在這樣的定義之下,就算 dependencies 裡面引入了其他會使用不同版本的 guava
也不會導致打包過程弄錯版本,進而更好地掌握打包的結果、避免版本衝突的議題產生。
沒有留言:
張貼留言