不常見的狀況,假設 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 進來。
---
---
沒有留言:
張貼留言