Maven pom管理相依lib - 排除不要的版本與避免下游過度包含不需要的lib

在公司裡,我們是使用Maven專案來管理專案的程式lib相依性,
相較於古早年代(大概是我剛來的9年前),各種lib都自己上網抓下來copy在自己的硬碟裡的作法,
Maven確實讓lib管理工作大幅簡化,也避免了程式上線後在runtime環境才發現缺東缺西的冏境。

想到以前剛接研發工作之時,前輩copy了一堆專案程式的檔案給我,
但我怎樣就是無法在本機完成build!  才發現原來專案還有引用到其他目錄的某個lib...
接手維護程式好一陣子之後,總搞不清楚專案中一大堆lib是否都有用處?
但這些legacy專案,缺少文件與原創者的情況下,就沒人敢隨意更動了~~

直到數年前,部門引入了CI思維,採用Maven+Nexus+Jenkins等技術,
才讓我開始將舊專案重新拆解,改成Maven之後,這些lib的相依性就有了很好的管理。

Maven pom的lib管理,會自動將指定lib所相依的其他lib自動帶入;
而當同lib有多個版本的時候,會自動排除掉舊版本的lib。
所以開發者不用費很多心思去查找這些lib的複雜相依性,
專注在需要使用的功能以及要開發的功能就好了。

不過,這麼方便的功能,也同時帶來了一些可能以前沒遇過的問題:
  1. 專案裡有許多lib是自己使用而不需要被其他的下游專案所使用,但pom一旦設定引用,就會連帶將所有相依lib都帶給下游專案,可能包進了不需要使用的lib或是造成lib的版本相衝突
  2. 專案裡引用了某些lib會使用到另一個lib,然而程式實際上沒使用到另一個lib的功能,而且它是具有資安風險的版本,而我不知道怎麼將它排除掉
想要解決這兩個問題,除了網路上常見到的dependency exclude (像是這篇 文章)之外,還有其他更方便的解決方案。

將Dependency設定為optional

情境描述

假設有A, B, C三個專案,A用到B,B用到C,但是A不需要用到C。
這時可以在B的pom.xml設定C為optional(設定1),這樣A就不會把C抓進來(設定2)。
但相對的,如果有D專案同時要用B跟C,就必須在dependency中宣告B跟C(設定3)。

設定內容

(設定1) B: B用到C,但是認為其他人不一定需要C
<dependency>
 <groupId>test</groupId>
 <artifactId>C</artifactId>
 <version>0.0.18</version>
 <optional>true</optional>
</denpendency>

(設定2) A: A用到B,但是A不需要用到C
<dependency>
 <groupId>test</groupId>
 <artifactId>B</artifactId>
 <version>0.0.18</version> 
</denpendency>

(設定3) D:同時要用B跟C,就必須在dependency中宣告B跟C
<dependency>
 <groupId>bss</groupId>
 <artifactId>B</artifactId>
 <version>0.0.18</version> 
</denpendency>
<dependency>
 <groupId>bss</groupId>
 <artifactId>C</artifactId>
 <version>0.0.18</version> 
</denpendency>

將Dependency中排除(不包入)指定版本範圍的lib

情境描述

假設有A, B, C三個專案,A用到commons-fileupload的lib,B引用A,C也引用A。
在一般的情境中,B和C也都會連帶引用commons-fileupload(即使runtime沒使用到這功能)。
但commons-fileupload在1.3.3之前的版本被認定有資安風險,需要排除較舊的版本,以往的做法是在B/C等其他使用到A專案的pom裡加上exclude的設定。
不過commons-fileupload有多種版本被其他不同lib所引用時,只exclude單一版本的作法會無效(其他版本仍會被打包進來)。

設定內容

在B專案加上provided設定並指定版本範圍
<dependencies>
  <dependency>
      <artifactId>commons-fileupload</artifactId>
      <groupId>commons-fileupload</groupId>
      <version>[0.9,)</version>
      <scope>provided</scope>
  </dependency>
</dependencies>
[0.9,)的寫法是版本的起迄,表示從0.9版開始,因為,右邊沒指定版本,所以代表0.9版以上。
範例:[1.0,1.3.2) 表示1.0~1.3.2的版本範圍。
至於provided的用法,原本的意涵是使用runtime server上已提供的lib,所以打包時不需要加入jar/war/ear中。
透過這個特性,我們就能排開我們不需要的lib版本。

建立一個Parent專案(只有pom.xml)給所有專案繼承,在Parent專案中加上如上設定排除不要的lib
<parent>
        <groupId>com.cht</groupId>
        <artifactId>BL_Parent</artifactId>
        <version>1.0</version>
</parent>
如此一來,只須調整Parent設定,其他專案就能生效了!
<dependency>
      <artifactId>commons-fileupload</artifactId>
      <groupId>commons-fileupload</groupId>
      <version>1.3.3</version>
</dependency>
若有一個D專案真的要用到那個lib,可再額外加一條指定使用無問題的lib版本,就會被包進D專案中。

留言

這個網誌中的熱門文章