2012-09-26

Maven Dependency 進階設定(optional, version, exclusion)

optional

不常見的狀況,假設 A 專案有多種的存取資料庫實做方式,例如 Hibernate 與 iBatis,A 專案有一個抽象的介面與兩個實做,這兩個實做分別需要 Hibernate 與 iBatis 的 library。

當 B 專案引用 A 專案時,簡單的作法當然是,A 專案將兩種 library 都提供給 B 專案,這樣做可以減少困擾,但會讓 B 專案虛胖,因為只會用到一種實做方式。

精確的作法就是在 A 專案為這兩種 dependency 加上 optional 為 true 的設定,這樣當 B 專案引用 A 專案時,Maven 不會將 optional 為 true 的 dependency 塞到 B 專案裡,而 B 專案本身得在 pom.xml 裡加入想要使用的實做 library。

A 專案:
<dependency>
 <groupId>Hibernate</groupId>
 <artifactId>Hibernate</artifactId>
 <version>1</version>
 <optional>true</optional>
</dependency>
<dependency>
 <groupId>iBatis</groupId>
 <artifactId>iBatis</artifactId>
 <version>1</version>
 <optional>true</optional>
</dependency>
B 專案:
<dependency>
 <groupId>Hibernate</groupId>
 <artifactId>Hibernate</artifactId>
 <version>1</version>
</dependency>
聽說比較好的作法是用 Maven 的 Module,將不同的實作放到不同的 module,那個 B 專案在引用時就不會有這樣的困擾,但現階段還不會用 module,就先記著。


version

除了明寫版本以外,還有一些進階的用法。

[1.0,2.0] - 只接受 1.0 到 2.0 之間的版本。

[1.0,2.0) - 只接受 1.0 到 2.0 之間的版本,不包括 2.0。

[,2.0] - 只接受小於等於 2.0 的版本。

[,2.0) - 只接受小於 2.0 的版本,不包括 2.0。

[1.0] - 只接受 1.0 這個版本。

1.0 - 有 1.0 最好,沒有的話,任何版本都行(令人驚訝的定義)。

當一個專案的 dependency 變多之後,很容易出現相同的 groupId 與 artifactId,但不同的版本,這時候聰明的 Maven 會自己做決定,不同的版本像是 1.0 與 2.0 就沒有問題,若是 [1.0] 與 [2.0] 同時出現時,Maven 就會丟出錯誤。


exclusion

當前面提到的 dependency 衝突發生時,這時就得決定去留,這種情況多半發生在 transitive dependency,舉例說明,兩個 dependency 同時用到 commons-logging,但卻指定不同的版本,或甚至 groupId 不同,事實上是相同的 API(因為搬過家的關係),這時就得明確指定,哪個留哪個不留。

以實例說明,但使用 exclusion 不是因為 dependency 衝突,而是想要抽換實作方式,以 SLF4j 取代 Spring 預設的 Commons Logging。
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-webmvc</artifactId>
 <version>3.1.2.RELEASE</version>
 <scope>compile</scope>
 <!-- Spring 預設會使用 Commons Logging -->
 <!-- 但是想要使用 SLF4j 做 Logging -->
 <!-- 就得踢掉 Spring 裡的 Commons Logging -->
 <exclusions>
  <exclusion>
   <groupId>commons-logging</groupId>
   <artifactId>commons-logging</artifactId>
  </exclusion>
 </exclusions>
</dependency>
<!-- 使用 SLF4j 做 Logging -->
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-api</artifactId>
 <version>1.6.6</version>
 <scope>compile</scope>
</dependency>
<!-- SLF4j 為 Commons Logging 做的假介面 -->
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>jcl-over-slf4j</artifactId>
 <version>1.6.6</version>
 <scope>compile</scope>
</dependency>
<!-- 選擇 Log4j 作為 SLF4j 的實作 -->
<dependency>
 <groupId>org.slf4j</groupId>
 <artifactId>slf4j-log4j12</artifactId>
 <version>1.6.6</version>
 <scope>compile</scope>
</dependency>

可能使用 exclusion 的狀況:
  • 最常見的狀況就是抽換實作,像是上面提到的 SLF4j,或者 JTA 這個因為有版權而不能放到 Maven Repository 的 library,就可以改用 Apache Geronimo。
  • 像上面 optional 提到的狀況,提供多種實作但卻未使用 optional,導致引入各種實作的 library。
  • Library 搬過家,導致引入兩種 groupId 與 artifactId 不同,但是相同的 API。
  • 執行環境已經提供的 library,就不應該 transitive 進來。
---
---
---

沒有留言:

張貼留言