天天看點

關于maven可選依賴和排除依賴的學習 關于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層上?

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

繼續閱讀