Maven optional關鍵字透徹圖解

發表於2019-11-05

寫在前面

本來想寫一篇「如何自定義Spring Boot Starter」,但是為了更好理解 Starter 的一些設計理念和其中的關鍵點,所以提前將一些細節內容單獨提取出來講解說明

在 Maven pom.xml 中,你經常會看到依賴項中有類似下面的程式碼:

<dependency>
  <groupId>sample.ProjectA</groupId>
  <artifactId>Project-A</artifactId>
  <version>1.0</version>
  <scope>compile</scope>
  <optional>true</optional> 
</dependency>

這裡的 <optional>true</optional> 是什麼意思呢?

optional 關鍵字的奧祕

老規矩,畫個圖說明問題:

由於 project C 使用到了兩個來自 project A 的類 (OptionalFeatureAClass) 和 project B 的類 (OptionalFeatureBClass). 如果 project C 沒有依賴 packageA 和 packageB,那麼編譯將會失敗。

project D 依賴 project C,但是對於 project D 來說,類 (OptionalFeatureAClass) 和類 (OptionalFeatureBClass) 是可選的特性,所以為了讓最終的 war/ejb package 不包含不必要的依賴,使用<optional> 宣告當前依賴是可選的, 預設情況下也不會被其他專案繼承(好比 Java 中的 final 類,不能被其他類繼承一樣)

如果 project D 確實需要用到 project C 中的 OptionalFeatureAClass 怎麼辦呢?那我們就需要在 project D 的 pom.xml 中顯式的新增宣告 project A 依賴,繼續看下圖:

Project D 需要用到 Project A 的 OptionalFeatureAClass,那麼需要在 Project D 的 pom.xml 檔案中顯式的新增對 Project A 的依賴

到這也就很好理解為什麼 Maven 為什麼要設計 optional 關鍵字了,假設一個關於資料庫持久化的專案(Project C), 為了適配更多型別的資料庫持久化設計,比如 Mysql 持久化設計(Project A) 和 Oracle 持久化設計(Project B),當我們的專案(Project D) 要用的 Project C 的持久化設計,不可能既引入 mysql 驅動又引入 oracle 驅動吧,所以我們要顯式的指定一個,就是這個道理了

實際案例

spring-boot-actuator pom.xml 檔案中,有超過 20 個依賴是 optional

因為 Spring Boot 不可能將沒必要的依賴也打包到你最終的 jar package 中,所以用到 spring boot actuator 的專案最終生成的 jar package 中不會包含這 20 多個依賴 jar,如果你要用到哪一個,顯式的加入到你的專案就好了

在接下來的文章,自定義 Spring Boot Starter 也是這個策略,因為 starter 是包含特定功能為其他專案服務用的,類似本文的 Project C 的角色了,到這裡你理解 optional 的奧祕了嗎?

反向應用

如果 Project C 引入的依賴沒有加 <optional>true</optional>,Project D 又需要依賴 Project C,但只用到 Project A 的類怎麼辦呢?Maven 也是有解決辦法的,使用 exclusion 關鍵字,不多說,上一段程式碼就懂了:

<dependencies>
    <dependency>
      <groupId>top.dayarch.demo</groupId>
      <artifactId>Project-C</artifactId>
      <exclusions>
        <exclusion>
          <groupId>top.dayarch.demo</groupId>
          <artifactId>Project-B</artifactId>
        </exclusion>
      </exclusions> 
    </dependency>
</dependencies>

總結

到這裡,在你今後設計功能性依賴時,你應該明白怎樣設計依賴關係了, 我這裡推薦使用 optional 的形式,簡單來說,你設計的依賴什麼菜都有,想吃什麼菜自己 "抱蔡明" 就好,接下來我們就模擬官方標準建立自定義的 starter...... 部落格 訪問恢復正常,歡迎交流

靈魂追問

  1. 有很多童鞋專案組用的構建工具時 Gradle,你知道 Gradle 中是怎樣表示的嗎?
  2. 自定義 starter,你知道官方標準 starter 的結構是什麼樣的嗎?

提高效率工具


歡迎關注我的公眾號 「日拱一兵」,趣味原創解析Java技術棧問題,將複雜問題簡單化,將抽象問題圖形化落地
如果對我的專題內容感興趣,或搶先看更多內容,歡迎訪問我的部落格 dayarch.top