Maven(1)

座標詳解

Maven通過座標唯一標識一個組件。Maven座標是通過groupId、artifactId、version、packaging、classfier這些元素來定義的。

    <groupId>com.demon.study</groupId>
    <artifactId>log4jtest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

 

  • groupId

定義當前Maven項目隸屬的實際項目。首先,Maven項目和實際項目不一定是一對一的關係。比如SpringFrameWork這一實際項目,其對應的Maven項目會有很多,如spring-core,spring-context等。這是由於Maven中模塊的概念,因此,一個實際項目往往會被劃分成很多模塊。其次,groupId不應該對應項目隸屬的組織或公司。原因很簡單,一個組織下會有很多實際項目,如果groupId只定義到組織級別,而後面我們會看到,artifactId只能定義Maven項目(模塊),那麼實際項目這個層次將難以定義。最後,groupId的表示方式與Java包名的表達方式類似,通常與域名反向一一對應。上例中,groupId爲junit,是不是感覺很特殊,這樣也是可以的,因爲全世界就這麼個junit,它也沒有很多分支。

  • artifactId

該元素定義當前實際項目中的一個Maven項目(模塊),推薦的做法是使用實際項目名稱作爲artifactId的前綴。比如上例中的junit,junit就是實際的項目名稱,方便而且直觀。在默認情況下,maven生成的構件,會以artifactId作爲文件頭,如junit-3.8.1.jar,使用實際項目名稱作爲前綴,就能方便的從本地倉庫找到某個項目的構件。

  • version

該元素定義了使用構件的版本,如上例中junit的版本是3.8.1,你也可以改爲4.0表示使用4.0版本的junit。

  • packaging

定義Maven項目打包的方式,使用構件的什麼包。首先,打包方式通常與所生成構件的文件擴展名對應,如上例中沒有packaging,則默認爲jar包,最終的文件名爲junit-3.8.1.jar。也可以打包成war等。

  • classifier

該元素用來幫助定義構建輸出的一些附件。附屬構件與主構件對應,如上例中的主構件爲junit-3.8.1.jar,該項目可能還會通過一些插件生成如junit-3.8.1-javadoc.jar,junit-3.8.1-sources.jar, 這樣附屬構件也就擁有了自己唯一的座標。

上述5個元素中,groupId、artifactId、version是必須定義的,packaging是可選的(默認爲jar),而classfier是不能直接定義的,需要結合插件使用。

依賴

依賴配置

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			  <scope>test</scope> 
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.11.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>2.11.1</version>
		</dependency>
	</dependencies>

 dependencies可以包含一個或多個dependency。

包含元素有:

  • groupId
  • artifactId
  • version
  • type:依賴的類型。對應於項目座標定義的packaging。大部分情況下,不必聲明,默認爲jar。
  • classifier:依賴的分類器。分類器可以區分屬於同一個POM,但不同構建方式的構件。分類器名被附加到文件名的版本號後面。例如,如果你想要構建兩個單獨的構件成 JAR,一個使用Java 1.4編譯器,另一個使用Java 6編譯器,你就可以使用分類器來生成兩個單獨的JAR構件。
  • scope:依賴範圍。在項目發佈過程中,幫助決定哪些構件被包括進來
  • systemPath:僅供system範圍使用。注意,不鼓勵使用這個元素,並且在新的版本中該元素可能被覆蓋掉。該元素爲依賴規定了文件系統上的路徑。需要絕對路徑而不是相對路徑。推薦使用屬性匹配絕對路徑,例如${java.home}。
  • optional:可選依賴(true/false),如果你在項目B中把C依賴聲明爲可選,你就需要在依賴於B的項目(例如項目A)中顯式的引用對C的依賴。可選依賴阻斷依賴的傳遞性
  • exclusions:用來排除傳遞性依賴

依賴範圍

依賴範圍用來控制依賴與三種classpath(編譯classpath,測試classpath,運行classpath)之間的關係。

maven有以下幾種依賴:

  • compile :編譯依賴範圍。如果沒有指定,默認使用此範圍。對編譯,測試,運行都有效。典型例子spring-core。
  • provided:以提供依賴範圍。僅對編譯和測試有效。運行時無效。典型例子:servlet-api,運行時由容器提供。
  • runtime: 運行時依賴範圍。只在測試或運行時有效。編譯時無效。典型例子JDBC,
  • test: 測試依賴範圍。只對測試classpath有效。典型例子junit。
  • system: 系統依賴範圍。與classpath的關係與provided一致。但是必須通過systemPath來指定依賴文件的路徑
  • import:導入依賴範圍。不會對classpath產生影響。
依賴範圍

對於編譯

classpath有效

對於測試

classpath有效

對於運行

classpath有效

例子
compile Y Y Y spring-core
provided Y Y N servlet-api
runtime N Y Y JDBC
test N Y N junit
system Y Y N 本地文件。

 傳遞性依賴

依賴的傳遞性是指:在A 中添加對B 的依賴,在B 中添加對C 的依賴,如果依賴範圍是compile 的,A 不僅會有B 的jar 包,也會有C 的jar 包。如果在C 中添加了某個依賴,那麼根據傳遞性,A 和B 也可以使用C添加的依賴,而不需要自己再重新引入依賴
 

這裏寫圖片描述

傳遞性依賴與依賴範圍

依賴範圍不僅可以控制與3種classpath的關係,還對傳遞性依賴產生影響。

假設A依賴於B,B依賴於C,我們說A對於B是第一直接依賴,B對於C第二直接依賴,A對於C的傳遞性依賴。第一依賴的範圍和第二依賴的範圍決定了傳遞性的依賴範圍

依賴範圍影響傳遞性依賴

    \\\\\\\\\\      第二依賴

            \\\\\\\\\\

第一依賴      \\\\\\\\\\\\

compile test provided runtime
compile compile --- --- runtime
test test --- --- test
provided provided --- provided provided
runtime runtime --- --- runtime
  • 當第二直接依賴是compile範圍時。傳遞性依賴範圍與第一直接依賴相同。
  • 當第二直接依賴是test範圍時。依賴不傳遞。
  • 當第二直接依賴是provided範圍時。只傳遞provided依賴,並且傳遞依賴爲provided。
  • 當第二直接依賴是runtime範圍時。傳遞性依賴範圍與第一直接依賴相同。但compile會傳遞爲runtime

依賴調解

 針對於傳遞性依賴造成問題的時候,我們需要清楚知道傳遞性依賴的從哪條路徑引入的。例如A->B-C->X(1.0)  A->D

->X(2.0),兩條路徑有兩個版本的X,兩個版本都被解析是不對的,因爲會造成依賴重複,因此必須選擇一個。maven依賴調解(Dependency Mediation)

第一條原則是:路徑最近者優先。因此X(2.0)會被解析使用。

當路徑相同時我們採取

第二條原則,第一聲明者優先。即誰在pom文件中先聲明,先被解析。

可選依賴

假設A->B ,B->X(可選),B->Y(可選)。如果都是compile範圍,則X,Y是A的傳遞性compile範圍。但是由於X,Y是可選的,則依賴不會傳遞,即X,Y對A沒有任何影響。

爲什麼要使用可選依賴呢?假設項目B實現了2個特性,特性一依賴於X,特性二依賴於Y,但是X與Y互斥,例如B是持久層工具包,支持oracle,mysql等,構建項目時,只需要其中的一個。則A需要顯示聲明X或Y依賴

依賴排除

在依賴傳遞過程中,如A依賴B、S2.0,B依賴C、S1.0,這樣A就有了S1.0和S2.0兩個依賴,這樣某些情況下會造成衝突需要手動把B間接傳遞過來的依賴排除掉,就是不依賴B帶過來的S1.0的包。

我們在當前工程中引入了A 的依賴,而A 同時有對B 的依賴,根據傳遞性我們知道,在當前工程中會自動引入對B 的依賴。其中B 可能是一個不穩定的版本,或者對當前的工程存在着不良的影響 。這時我們就可以在引入對A 依賴的同時排除對B 的依賴。

使用exclusion來進行排除

<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>

 

 

 

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