【Maven】---座標與依賴
Maven座標與依賴
最近想深度學習下maven,找到一本書叫《Maven實戰》,這本書講的確實很好,唯一遺憾的是當時maven教學版本是3.0.0的,而目前已經到了3.5.4了,版本存在差距,
沒關係,如果有時間和精力我也會閱讀官方文件,看看到底有哪些變換。
一、座標詳解
1、何為Maven座標
maven定義了這樣一組規則:世界上任何一個構件都可以使用maven座標唯一標識,座標元素包括: groupId、artifactId、version、packaging、classifier 。只要提供正確
的座標就能從倉庫中找到相應的構件供我們使用。maven從哪裡下載構件呢?答:maven內建了一箇中央倉庫的地址,該中央倉庫包含了世界上大部分流行的開源構件。
2、座標詳解
任何構件都必須明確定義自己的座標,而一組maven座標是通過一些元素定義的,他們是:groupId、artifactId、version、packaging、classifier。先看一組座標定義如下
<groupId>org.sonatype.nexus</groupId> <artifactId>nexus-indexer</artifactId> <version>2.0.0</version> <packaging>jar</packaging>
這是nexus-indexer專案的座標,nexus-indexer是一個對maven倉庫編纂索引並提供搜尋功能的類庫,它是Nexus專案的一個子模組。
goupId : 定義了當前maven專案隸屬的實際專案,一般是域名+專案名。比如:com.alibaba.taotao
artifactId :該元素定義實際專案中的一個maven專案(模組,一般推薦專案名+子模組名。比如:taobao-web
version : 定義maven專案當前所處版本。
packaging :定義maven專案的打包方式,預設使用jar。
classifier :該元素用來幫助定義構件輸出的一些附屬構件。
上述5元素 groupId、artifactId、version是必須的 ,packaging可選,預設jar,classifier不能直接定義。同時,專案構件的檔名是與座標對應的,
一般的規則為artificatId-version[-classifier].packaging。packing並非一定與構件副檔名對應,比如packing為maven-plugin的構件副檔名為jar。
二、依賴詳解
1、依賴的配置
一般的依賴只有基本的 groupId,artifactId,version。我們來看下詳細的依賴配置
<project> <dependencies> ... <dependency> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version> <type>...</type> <scope>...</scope> <optional>...</optional> <exclusions> <exclusion> ... </exclusion> </exclusions> </dependency> ... </dependencies> </project>
gourpId、artifactId、version: 依賴的基本座標,對於任何一個依賴來說,基本座標是最重要的,maven根據座標才能找到需要的依賴。
type: 依賴的型別,對於專案座標定義的packing,大部分情況是不必宣告,預設是jar。
scope :依賴的範圍 下面具體講解
optional : 標記依賴是否可選,值為true或false,預設為false, 如果為可選依賴,則依賴不具有傳遞性。即B->X(可選依賴),A->B。此時A的依賴中不包含X。
exclusions: 用來排除傳遞性依賴。
大部分依賴宣告只包含基本座標,然而在一些特殊情況下,其他元素至關重要。
2、依賴範圍scope
classpath: 用於指定.class檔案存放的位置,類載入器會從該路徑中載入所需的.class檔案到記憶體中。maven在編譯、執行測試、實際執行有著三套不同的classpath。
編譯classpath :編譯主程式碼有效
測試classpath: 編譯、執行測試程式碼有效
執行classpath: 專案執行時有效
maven的依賴範圍
compile: 編譯依賴範圍。(預設方式),有效範圍:編譯classpath+測試classpath+執行classpath。
test: 測試依賴範圍。有效範圍:測試classpath 比如:JUnit,只在測試時使用,在編譯主程式碼和執行時不需要此依賴。
provided: 已提供依賴範圍。有效範圍:編譯classpath+測試classpath。
runtime: 執行時依賴範圍。有效範圍:測試classpath+執行classpath。比如:JDBC驅動實現(mysql-connector-java)。
system: 系統依賴範圍。有效範圍:編譯classpath+測試classpath。使用system範圍的依賴時必須通過systemPath元素顯示地指定依賴檔案的路徑,
因為此類依賴不是通過maven倉庫解析的,而且往往與本地及其系統繫結,可能造成構建的不可移植,慎用。systemPath元素可以引用環境變數。
<!--你引用本地的jar包,當然只能本地使用了--> <dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>${JAVA_HOME}/lib/rt.jar</systemPath> </dependency> <!--你會發現這裡這裡是test,那麼裡面有個@Test 註解 只能在test目錄下有效,在main目錄下該註解是無效的--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
3、傳遞依賴性
假設 A依賴B,B依賴C,則A對於B是第一直接依賴,B對於C是第二直接依賴,A對於C是傳遞性依賴 。第一直接依賴的範圍和第二直接依賴的範圍決定了傳遞性依賴的範圍。
如下表,最左邊是第一直接依賴範圍,上面是第二直接依賴範圍,中間交叉單元格表示傳遞性依賴範圍。
規律:
第二直接依賴範圍是compile時,傳遞依賴的範圍與第一直接依賴範圍一致。
第二直接依賴範圍是test時,依賴不會傳遞。
第二直接依賴範圍是provided時,只傳遞第一直接依賴為provided的依賴。
第二直接依賴範圍是runtime時,傳遞依賴的範圍與第一直接依賴範圍一致,但是compile例外,此時傳遞依賴範圍為runtime。
4、依賴調節
Maven引入的傳遞性依賴機制,一方面大大簡化和方便了依賴宣告,另一方面,大部 分情況下我們只需要關心項0的直接依賴是什麼,而不用考慮這些直接依賴會引人什麼傳 遞性依賴。
但有時候,當傳遞性依賴造成問題的時候,我們就需要清楚地知道該傳遞性依 賴是從哪條依賴路徑引入的。
例如,專案A有這樣的依賴關係:A->B->C->X(1.0)、A->D->X(2.0),X是A的 傳遞性依賴,但是兩條依賴路徑上有兩個版本的X,那麼哪個X會被Maven解析使用呢?
兩個版本都被解析顯然是不對的,因為那會造成依賴重複,因此必須選擇一個。Maven依 賴調解(Dependency Mediation)的第一原則是:
路徑最近者優先。 該例中X( 1.0)的路徑氏 度為3,而X(2.0)的路徑長度為2,因此X(2.0)會被解折使用。
依賴調解第一原則不能解決所有問題,比如這樣的依賴關係:A->B->Y(1.0)、A-> C->Y(2.0),Y(1.0)和Y(2.0)的依賴路徑長度是一樣的,都為2。Maven定義了依賴調解的第二原則:
第一宣告者優先 。在依 賴路徑長度相等的前提下,在POM中依賴宣告的順序決定了誰會被解析使用,順序最前的那個依賴優勝。該例中,如果B的依賴宣告在C之前,那麼Y (1.0)就會被解析使用.
5、排除依賴
傳遞性依賴會給專案引入很多依賴,簡化專案依賴管理,但是也會帶來問題。
需求 :比如當前專案有一個第三方依賴,而第三方依賴依賴了另一個類庫的SNAPSHOT版本,那麼這個SNAPSHOT就會成為當前專案的傳遞性依賴,而SNAPSHOT的不穩定性會直接影響到當前專案。
這時候就應該排除掉SNAPSHOT。並且宣告該類庫的正式釋出版本。
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>3.6.10.Final</version> <exclusions> <exclusion> <groupId>slf4j-api</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency>
上述程式碼中hibernate-validator依賴slf4j-api,但是當前專案不想使用傳遞過來的slf4j-api,所以通過 exclusions 宣告排除依賴。當前專案聲明瞭自己需要的1.7.12版本的slf4j-api。
exclusions可以包含一個或者多fexdWon子元素,因此可以排除一個或者多 個傳遞性依賴 。需要注意的是,宣告exclusion的時候只需要groupld和artifactld,而不 笛要version元素,
這是因為只需要gmupkl和arlifactid就能唯一定位依賴圖中的某個依 賴。換句話說,Maven解析後的依賴中,不可能出現groupW和artifactld相同,但是 version不同的兩個依賴。
注意: 排除依賴的時候也要注意,比如A依賴1.1版本的B, ,而你不想要1.1版本的B,而是要2.1的B,這個時候也需要考慮A跟2.1的B是否能相容。
6、歸類依賴
需求 :關於springframework的依賴有好多,org.springframework:spirng-core:2.5.6、org.springframework:sprng-beans:2.5.6、org.springframework:spring-context:2.5.6,
他們來自同一個專案不同模組,因此版本都是相同的,可以預見在升級spring時這些依賴都會一起升級,為了方便統一所以使用properties元素定義maven屬性。
<project> .... <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <springframework.version>4.3.2.RELEASE</springframework.version> </properties> <!--通過使用${springframework.version}替換掉實際值,將所有spring依賴的版本值都使用這一引用值表示。--> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> </dependencies> ... </project>
參考
《Maven實戰》. 許曉斌
同時很高興,找到看過這本書的人的總結。
座標詳解: ofollow,noindex">https://www.jianshu.com/p/30ece967dccd
依賴配置: https://www.jianshu.com/p/79cf4423281a
我只是偶爾安靜下來,對過去的種種思忖一番。那些曾經的舊時光裡即便有過天真愚鈍,也不值得譴責。畢竟,往後的日子,還很長。不斷鼓勵自己,
天一亮,又是嶄新的起點,又是未知的征程(上校20)