1. 程式人生 > >Maven之(九)依賴關係

Maven之(九)依賴關係

在maven的管理體系中,各個專案組成了一個複雜的關係網,但是每個專案都是平等的,是個沒有貴賤高低,眾生平等的世界,全球每個專案從理論上來說都可以相互依賴。就是說,你跟開發Spring的大牛們平起平坐,你的專案可以依賴Spring專案,Spring專案也可以依賴你的專案(雖然現實中不太會發生,你倒貼錢人家也不敢引用)。

專案的依賴關係主要分為三種:依賴,繼承,聚合

依賴關係

依賴關係是最常用的一種,就是你的專案需要依賴其他專案,比如Apache-common包,Spring包等等。

<dependency>
               <groupId>junit</groupId>
               <artifactId>junit</artifactId>
               <version>4.11</version>
               <scope>test</scope>
               <type >jar</ type >
               <optional >true</ optional >
 </dependency>

任意一個外部依賴說明包含如下幾個要素:groupId, artifactId, version, scope, type, optional。其中前3個是必須的。

這裡的version可以用區間表示式來表示,比如(2.0,)表示>2.0,[2.0,3.0)表示2.0<=ver<3.0;多個條件之間用逗號分隔,比如[1,3],[5,7]。

type 一般在pom引用依賴時候出現,其他時候不用。

maven認為,程式對外部的依賴會隨著程式的所處階段和應用場景而變化,所以maven中的依賴關係有作用域(scope)的限制。在maven中,scope包含如下的取值:

Scope選項

compile(編譯範圍)

compile是預設的範圍;如果沒有提供一個範圍,那該依賴的範圍就是編譯範圍。編譯範圍依賴在所有的classpath中可用,同時它們也會被打包。

provided(已提供範圍)

provided依賴只有在當JDK或者一個容器已提供該依賴之後才使用。例如,如果你開發了一個web應用,你可能在編譯classpath中需要可用 的Servlet API來編譯一個servlet,但是你不會想要在打包好的WAR中包含這個Servlet API;這個Servlet API JAR由你的應用伺服器或者servlet容器提供。已提供範圍的依賴在編譯classpath(不是執行時)可用。它們不是傳遞性的,也不會被打包。

runtime(執行時範圍)

runtime依賴在執行和測試系統的時候需要,但在編譯的時候不需要。比如,你可能在編譯的時候只需要JDBC API JAR,而只有在執行的時候才需要JDBC驅動實現。

test(測試範圍)

test範圍依賴在編譯和執行時都不需要,它們只有在測試編譯和測試執行階段可用。

system(系統範圍)

system範圍依賴與provided類似,但是你必須顯式的提供一個對於本地系統中JAR檔案的路徑。這麼做是為了允許基於本地物件編譯,而這些物件是系統類庫的一部分。這樣的構件應該是一直可用的,Maven也不會在倉庫中去尋找它。 如果你將一個依賴範圍設定成系統範圍,你必須同時提供一個systemPath元素 。注意該範圍是不推薦使用的(應該一直儘量去從公共或定製的Maven倉庫中引用依賴)。


dependency中的type一般不用配置,預設是jar。當type為pom時,代表引用關係:

<dependency>
     <groupId>org.sonatype.mavenbook</groupId>
     <artifactId>persistence-deps</artifactId>
     <version>1.0</version>
     <type>pom</type>
</dependency>

此時,本專案會將persistence-deps的所有jar包匯入依賴庫。

可以建立一個打包方式為pom專案來將某些通用的依賴歸在一起,供其他專案直接引用,不要忘了指定依賴型別為pom(<type>pom</type>)。

繼承關係

繼承就是避免重複,maven的繼承也是這樣,它還有一個好處就是讓專案更加安全。專案之間存在上下級關係時就屬於繼承關係。

父專案的配置如下:

<project>  
	  <modelVersion>4.0.0</modelVersion>  
	  <groupId>org.clf.parent</groupId>  
	  <artifactId>my-parent</artifactId>  
	  <version>2.0</version>  
	  <packaging>pom</packaging> 
	  
	  <!-- 該節點下的依賴會被子專案自動全部繼承 -->
	  <dependencies>
  	    <dependency>
               <groupId>org.slf4j</groupId>
               <artifactId>slf4j-api</artifactId>
               <version>1.7.7</version>
               <type>jar</type>
               <scope>compile</scope>
        </dependency>
	  </dependencies>
	  
	  <dependencyManagement>
        <!-- 該節點下的依賴關係只是為了統一版本號,不會被子專案自動繼承,-->
        <!--除非子專案主動引用,好處是子專案可以不用寫版本號 -->
        <dependencies>
           <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>4.2.5.RELEASE</version>
            </dependency>
        </dependencies>
       </dependencyManagement>

       <!-- 這個元素和dependencyManagement相類似,它是用來進行外掛管理的-->
       <pluginManagement>  
       ......
       </pluginManagement>
</project>

注意,此時<packaging>必須為pom

為了專案的正確執行,必須讓所有的子專案使用依賴項的統一版本,必須確保應用的各個專案的依賴項和版本一致,才能保證測試的和釋出是相同的結果。

Maven 使用dependencyManagement 元素來提供了一種管理依賴版本號的方式。通常會在一個組織或者專案的最頂層的父POM 中看到dependencyManagement 元素。使用pom.xml 中的dependencyManagement 元素能讓所有在子專案中引用一個依賴而不用顯式的列出版本號。Maven 會沿著父子層次向上走,直到找到一個擁有dependencyManagement元素的專案,然後它就會使用在這個dependencyManagement 元素中指定的版本號。

 父專案在dependencies宣告的依賴,子專案會從全部自動地繼承。而父專案在dependencyManagement裡只是宣告依賴,並不實現引入,因此子專案需要顯示的宣告需要用的依賴。如果不在子專案中宣告依賴,是不會從父專案中繼承下來的;只有在子專案中寫了該依賴項,並且沒有指定具體版本,才會從父專案中繼承該項,並且version和scope都讀取自父pom另外如果子專案中指定了版本號,那麼會使用子專案中指定的jar版本。

如果某個專案需要繼承該父專案,基礎配置應該這樣:

<project>  
	  <modelVersion>4.0.0</modelVersion>  
	  <groupId>org.clf.parent.son</groupId>  
	  <artifactId>my-son</artifactId>  
	  <version>1.0</version> 
	  <!-- 宣告將父專案的座標 -->
	  <parent>
		  <groupId>org.clf.parent</groupId>  
		  <artifactId>my-parent</artifactId>  
		  <version>2.0</version>  
		  <!-- 父專案的pom.xml檔案的相對路徑。相對路徑允許你選擇一個不同的路徑。 -->
		  <!--	預設值是../pom.xml。Maven首先在構建當前專案的地方尋找父專案的pom, -->
		  <!--	其次在檔案系統的這個位置(relativePath位置), -->
		  <!--	然後在本地倉庫,最後在遠端倉庫尋找父專案的pom。 -->
		  <relativePath>../parent-project/pom.xml</relativePath>
	  </parent> 
	  
	  <!-- 宣告父專案dependencyManagement的依賴,不用寫版本號 -->
	  <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-web</artifactId>
          </dependency>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-beans</artifactId>
          </dependency>
      </dependencies>
	   
</project>

聚合關係

隨著技術的飛速發展和各類使用者對軟體的要求越來越高,軟體本身也變得越來越複雜,然後軟體設計人員開始採用各種方式進行開發,於是就有了我們的分層架構、分模組開發,來提高程式碼的清晰和重用。針對於這一特性,maven也給予了相應的配置。

maven的多模組管理也是非常強大的。一般來說,maven要求同一個工程的所有模組都放置到同一個目錄下,每一個子目錄代表一個模組,比如

總專案/

     pom.xml 總專案的pom配置檔案

     子模組1/

           pom.xml 子模組1的pom檔案

     子模組2/

          pom.xml子模組2的pom檔案

總專案的配置如下:

<project> 
       <modelVersion>4.0.0</modelVersion> 
       <groupId>org.clf.parent</groupId> 
       <artifactId>my-parent</artifactId> 
       <version>2.0</version> 
       
       <!-- 打包型別必須為pom -->
       <packaging>pom</packaging>
       
       <!-- 聲明瞭該專案的直接子模組 -->
       <modules>
       <!-- 這裡配置的不是artifactId,而是這個模組的目錄名稱-->
        <module>module-1</module>
        <module>module-2</module>
        <module>module-3</module>
    </modules>
       
       <!-- 聚合也屬於父子關係,總專案中的dependencies與dependencyManagement、pluginManagement用法與繼承關係類似 -->
       <dependencies>
        ......
       </dependencies>
        
       <dependencyManagement>
        ......
       </dependencyManagement>
 
       <pluginManagement> 
       ......
       </pluginManagement>
</project> 
 

子模組的配置如下: 

<project> 
       <modelVersion>4.0.0</modelVersion> 
       <groupId>org.clf.parent.son</groupId> 
       <artifactId>my-son</artifactId> 
       <version>1.0</version>
       <!-- 宣告將父專案的座標 -->
       <parent>
              <groupId>org.clf.parent</groupId> 
              <artifactId>my-parent</artifactId> 
              <version>2.0</version> 
       </parent>
</project>

繼承與聚合的關係

首先,繼承與聚合都屬於父子關係,並且,聚合 POM與繼承關係中的父POM的packaging都是pom。

不同的是,對於聚合模組來說,它知道有哪些被聚合的模組,但那些被聚合的模組不知道這個聚合模組的存在。對於繼承關係的父 POM來說,它不知道有哪些子模組繼承與它,但那些子模組都必須知道自己的父 POM是什麼。

在實際專案中,一個 POM往往既是聚合POM,又是父 POM,它繼承了某個專案,本身包含幾個子模組,同時肯定會存在普通的依賴關係,就是說,依賴、繼承、聚合這三種關係是並存的。

Maven可繼承的POM 元素列表如下:

groupId :專案組 ID ,專案座標的核心元素;

version :專案版本,專案座標的核心元素;

description :專案的描述資訊;

organization :專案的組織資訊;

inceptionYear :專案的創始年份;

url :專案的 url 地址

develoers :專案的開發者資訊;

contributors :專案的貢獻者資訊;

distributionManagerment:專案的部署資訊;

issueManagement :缺陷跟蹤系統資訊;

ciManagement :專案的持續繼承資訊;

scm :專案的版本控制資訊;

mailingListserv :專案的郵件列表資訊;

properties :自定義的 Maven 屬性;

dependencies :專案的依賴配置;

dependencyManagement:醒目的依賴管理配置;

repositories :專案的倉庫配置;

build :包括專案的原始碼目錄配置、輸出目錄配置、外掛配置、外掛管理配置等;

reporting :包括專案的報告輸出目錄配置、報告外掛配置等。