在比較大型的專案中使用 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 檔內容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <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 這個套件。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <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
也不會導致打包過程弄錯版本,進而更好地掌握打包的結果、避免版本衝突的議題產生。
沒有留言:
張貼留言