Maven BOM!拿來吧你

  • 2021 年 7 月 25 日
  • 筆記

what BOM?

BOM(Bill of Materials)是由Maven提供的功能,它通過定義一整套相互兼容的jar包版本集合,

使用時只需要依賴該BOM文件,即可放心的使用需要的依賴jar包,且無需再指定版本號

BOM的維護方負責版本升級,並保證BOM中定義的jar包版本之間的兼容性。

why BOM?

使用BOM除了可以方便使用者在聲明依賴的客戶端時不需要指定版本號外,

最主要的原因是可以解決依賴衝突,如考慮以下的依賴場景:

項目A依賴項目B 2.1和項目C 1.2版本:

項目B 2.1依賴項目D 1.1版本;

項目C 1.2依賴項目D 1.3版本;

在該例中,項目A對於項目D的依賴就會出現衝突,按照maven dependency mediation的規則,最後生效的可能是:項目A中會依賴到項目D1.1版本(就近原則,取決於路徑和依賴的先後,和Maven版本有關係)。

在這種情況下,由於項目C依賴1.3版本的項目D,但是在運行時生效的確是1.1版本,

所以在運行時很容易產生問題,如 NoSuchMethodError, ClassNotFoundException等,

有些jar包衝突定位還是比較難的,這種方式可以節省很多定位此類問題的時間。

Spring、SpringBoot、SpringCloud自身都採用了此機制來解決第三方包的衝突,

常見官方提供的BOM:

1) RESTEasy Maven BOM dependency

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.resteasy</groupId>
            <artifactId>resteasy-bom</artifactId>
            <version>3.0.6.Final</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2. JBOSS Maven BOM dependency

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.jboss.bom</groupId>
            <artifactId>jboss-javaee-6.0-with-tools</artifactId>
            <version>${some.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement> 

3) Spring Maven BOM dependency

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-framework-bom</artifactId>
            <version>4.0.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

4) Jersey Maven BOM dependency

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

5) SpringCloud SpringBoot Maven BOM dependency

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.4.4</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2020.0.2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

看著有點蒙不要緊,下面會詳細介紹這些配置的作用

自己開發的項目中也建議使用此優良傳統, 尤其實在項目開發初期,在後期再修改成BOM可能涉及很多版本的修改,就比較難了。

how BOM?

定義BOM

BOM本質上是一個普通的POM文件,區別是對於使用方而言,生效的只有 <dependencyManagement>這一個部分。

只需要在<dependencyManagement>定義對外發布的客戶端版本即可,

比如需要在項目中統一所有SpringBoot和SpringCloud的版本

第一步需要在POM文件中增加兩個的官方BOM,以目前最新穩定的SpringBoot版本為例,使用官方推薦的版本組合比較穩定,一般不會有什麼大的問題

image.png

<groupId>com.niu.not</groupId>
<artifactId>niu-dependency</artifactId>
<version>1.1.1</version>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.4.6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2020.0.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.6</version>
    </dependency>
</dependencies>

下面的Gson是除了SpringBoot和SpingCloud外需要統一版本的jar

其他工程使用方法

在項目主pom.xml文件中<dependencyManagement></dependencyManagement>節點下加入BOM的GAV資訊如下:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.niu.not</groupId>
            <artifactId>niu-dependency</artifactId>
            <version>1.1.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

在需要使用相關JAR包的pom.xml文件中<dependencies></dependencies>節點下引入如下:

<dependencies>
    <!--此時用到Spring和Gson都不需要加版本號,會自動引用BOM中提供的版本-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
    </dependency>
</dependencies>

這種設置後,如果項目要求升級Spring版本,只需要在提供方升級驗證兼容性,然後修改BOM依賴即可

如果需要使用不同於當前bom中所維護的jar包版本,則加上<version>覆蓋即可,如:

<dependencies>
    <!--此時用到Spring和Gson都不需要加版本號,會自動引用BOM中提供的版本-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <!--會覆蓋掉BOM中聲明的版本2.8.6,使用自定義版本2.8.2-->
        <version>2.8.2</version>
    </dependency>
</dependencies>

小結

Jar包衝突非常煩人,Spring框架相關的衝突,有些報錯非常不清晰或者根本不報錯直接停止服務,

這種問題很難定位,開發人員應該聚焦業務開發,不應該在這上面浪費過多時間,

所以統一的版本管理還是非常有用的,不然Spring的牛逼框架為啥都在用呢,

BOM管理,拿來吧你!!!

參考://howtodoinjava.com/maven/maven-bom-bill-of-materials-dependency/