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 :包括專案的報告輸出目錄配置、報告外掛配置等。