關於maven可選依賴和排除依賴的學習

關於maven可選依賴和排除依賴的學習

      

      瞭解可選依賴和排除依賴的功能,能夠幫助我們更好的理解依賴是什麼、怎樣使用、如何工作和何時最適宜應用。其中,排除依賴是作爲依賴的基本概念而不是處於pom層。

一、    可選依賴

       當一個項目不適合分割成多個子模塊的時候,我們可以使用可選依賴。它的思想在於某些依賴只應用於某些功能,而且當沒有該功能時也不存在該依賴。理想狀況下,一個功能可能被劃分爲一個子模塊,該子模塊是一個只有核心功能的項目,由於當你要使用這個子工程的功能的時候,你會需要它的全部,所以這個子工程只含有非可選性依賴。

      然而,如果工程不可被分割,這些依賴被聲明爲可選。如果一個用戶想要使用和可選性依賴相關的功能,他們必須要在工程中重新聲明可選性依賴。也許可選依賴和排除依賴不是解決問題的最好方法,但是不失爲一種有效的解決方案。

      1. 爲何使用可選依賴

      聲明可選依賴不僅對於節省空間/內存等是重要的,而且對於使用一個工程的時候控制實際依賴的列表也是非常重要的。因爲jar包最終可能編譯成WAR、EAR、EJB等等,包含錯誤的jar包可能產生違反許可證協議、導致類路徑錯誤等問題。

      2.如何使用optional標記

      在你的依賴聲明中簡單地將<optional>標記設置成true,就能將一個依賴聲明爲可選的。示例如下

<project>
  ...
  <dependencies>
    <!-- declare the dependency to be set as optional -->
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <optional>true</optional> <!-- value will be true or false only -->
    </dependency>
  </dependencies>
</project>

      3.可選依賴是如何工作的?

Project-A -> Project-B

      如上圖所以projectA依賴projectB,當A在它的pom中聲明B作爲它的可選依賴時,這個關係會一直保持。 這就像在通常的構建中,projectB會被加到它的類路徑中。

Project-X -> Project-A

      但是當另外一個工程projectX在它的pom中聲明A作爲其依賴時,可選性依賴這時就發揮作用了。你會發現projectB並不存在projectX的類路徑中。如果X的類路徑要包含B那麼需要在你的pom中直接進行聲明。

      4.例子:

      讓我們假設現在有這樣一個和hibernate有類似功能的工程X2,支持多種諸如MySQL, postgre, Oracle數據庫驅動/依賴,所有這些驅動/依賴是X2但不是你的工程所需要的,所以一種比較可行的方法就是X2將這些驅動/依賴聲明爲可選的。這樣,無論任何時候當你的工程在pom中聲明X2作爲直接依賴,X2所支持的這些驅動/依賴都不會被自動加到你工程的類路徑中,相反地,你必須要直接聲明需要使用的數據庫驅動/依賴。

二、  排除依賴

       由於maven2.x會傳遞解析依賴,所以很有可能一些你不需要的依賴也會包含在工程類路徑中。例如,一些你依賴的工程可能沒有正確的聲明它們的依賴集。爲了解決這種特殊情況,maven2.x已經引入了顯式排除依賴的概念。排除是設置在pom中指定的依賴上,並且有指定的groupId和artifactId來標註。當你構建工程時,該物件不會像解析加載依賴一樣被加載到你工程的類路徑中。

       1. 如何使用排除依賴

       我們在pom中的<dependency>段下面加上<exclusions>標籤。

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectA</groupId>
      <artifactId>Project-A</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>  <!-- declare the exclusion here -->
          <groupId>sample.ProjectB</groupId>
          <artifactId>Project-B</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</project>

       2.排除依賴是如何工作的並且在何時使用它(作爲最後一種解決方法)

Project-A
   -> Project-B
        -> Project-D <! -- This dependency should be excluded -->
              -> Project-E
              -> Project-F
   -> Project C

       如上圖所示,Project-A依賴Project-B和C,Project-B依賴Project-D,Project-D依賴Project-E和F,默認的Project-A的類路徑會包含:

B, C, D, E, F

       如果由於我們知道Project-D的某些依賴在倉庫中丟失,那麼我們不想Project-D和它所有的依賴加載到Project-A的類路徑中,而且也不想/不需要依賴Project-D的Project-B的功能。在這種情況下,Project-B的開發者會提供一個Project-D的 <optional>true</optional>依賴,如下:

<dependency>
  <groupId>sample.ProjectD</groupId>
  <artifactId>ProjectD</artifactId>
  <version>1.0-SNAPSHOT</version>
  <optional>true</optional>

</dependency>

      然而,並不能達到你想要的效果。作爲最後一種解決方法你仍然可以選擇將它在Project-A中排除掉。如下:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.ProjectA</groupId>
  <artifactId>Project-A</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectB</groupId>
      <artifactId>Project-B</artifactId>
      <version>1.0-SNAPSHOT</version>
      <exclusions>
        <exclusion>
          <groupId>sample.ProjectD</groupId> <!-- Exclude Project-D from Project-B -->
          <artifactId>Project-D</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
</project>

      如果我們將Project-A部署到一個倉庫中,而且Project-X聲明瞭一個普通依賴到Project-A。那麼Project-D是不是依舊從類路徑中排除了?

Project-X -> Project-A

       答案是yes。Project-A已經聲明瞭它不需要Project-D,所以它不會作爲Project-A的傳遞依賴而引入。那麼考慮下圖的Project-X依賴Project-Y,

Project-X -> Project-Y
               -> Project-B
                    -> Project-D
                       ...

       Project-Y依賴於Project-B,並且它有需要Project-D所支持的功能,所以不能在Project-D的依賴列表中聲明排除。也可再提供一個額外的我們可以解析Project-E的倉庫。在這種情況下,不能將Project-D全局排除,因爲它是Project-Y的合法依賴。

      在另外一種場景中,如果我們不需要的依賴是Project-E而不是Project-D,我們如何排除它呢?如下圖:

Project-A
   -> Project-B
        -> Project-D
              -> Project-E <!-- Exclude this dependency -->
              -> Project-F
   -> Project C

      排除會影響到在依賴圖上所有它的聲明點以後的部分。如果你想排除Project-E而不是Project-D,可以簡單的將排除指向Project-E。但是你無法將排除作用到Project-D,因爲你無法改變Project-D的pom,如果你想這樣,你應該用選擇依賴而不是排除,或者將Project-D分成多個子工程,每個只有普通依賴。

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>sample.ProjectA</groupId>
  <artifactId>Project-A</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  ...
  <dependencies>
    <dependency>
      <groupId>sample.ProjectB</groupId>
      <artifactId>Project-B</artifactId>
      <version>1.0-SNAPSHOT</version>
      <exclusions>
        <exclusion>
          <groupId>sample.ProjectE</groupId> <!-- Exclude Project-E from Project-B -->
          <artifactId>Project-E</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencie>

      3.爲什麼排除是依賴的基本概念,而不是在pom層上?

       這主要是爲了確保依賴圖是可預測的,並且防止排除不該排除的依賴。如果你用到了這個最終的解決方法並且必須要把它放到排除中,你必須絕對清楚你討厭的傳遞依賴中有哪些依賴會被引入。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章