Maven-Dependency Mechanism
依賴管理是maven的一個廣為人知的特性, 這也是maven擅長的一個領域. 為單一的工程管理依賴不是很難, 但當你著手處理多模塊工程和包含數十或數百個模塊的應用時, maven可以幫助你很好地保持高度控制和穩定性.
Transitive Dependencies
依賴傳遞性是 maven 2.0中的一個新特性. 這不需要你去搜索和指定你自己的依賴需要的庫, 而是自動地包含它們.
這個特性通過從指定的遠程倉庫讀取你依賴的工程文件. 通常, 那些工程的所有依賴關系都會用于你的工程, 因為該項目從其父母或依賴關系中繼承了這些.?
沒有限制依賴的組織層次數目, 但如果發現一個循環依賴就會發生問題.
由于依賴傳遞, 包含庫的關系圖會迅速變得很大. 因此, 有一些額外的特性來限制哪些依賴被包含:
(1) Dependency mediation. 依賴調解. 這決定了, 當一個構件的多個版本相遇時, 使用哪個版本的依賴. 目前, maven 2.0 只支持使用最近的定義("nearest definition"), 就是說, 它將使用在依賴樹中離你的項目最近的版本. 你可以顯式地在項目的pom文件中聲明, 保證總是使用某個特定的版本. 注意, 如果2個依賴版本在依賴樹中的深度一樣, 在maven 2.0.8之前, 它沒有定義哪個版本會勝出, 但從maven 2.0.9, 由聲明的順序來決定, 第一聲明者優先.
nearest definition, 是指在依賴樹中離你的工程最近的那個版本. 比如, 如果A,B,C之間的依賴關系為: A->B->C->D 2.0, 以及 A->E->D 1.0, 這樣, 當構建A時, 將會使用 D 1.0. 因為從A到D的路徑, 后者更短.? 你可以顯式地在A中添加一個依賴 D 2.0, 強制使用D 2.0.
(2) Dependency management. 依賴管理. 當構件在依賴傳遞中 或沒有指定版本的依賴中相遇時, 工程作者可以直接 指定使用構件的哪個版本. 在上一節的例子中, 一個依賴會被添加到A中, 即使它不是直接被A使用. 相反, A可以在它的依賴管理中包含D作為一個依賴, 直接控制D在被引用時使用哪個版本.
(3) Dependency scope. 依賴范圍. 只包含適合當前構建階段的依賴. 下面會詳細描述這一點.
(4) Excluded dependencies. 排除依賴. 如果工程X依賴工程Y, 工程Y依賴工程Z, 工程X的所有者可以顯式地排除工程Z作為一個依賴, 使用 exclusion 元素 .
(5) Optional dependencies. 可選依賴. 如果工程Y依賴工程Z, 工程Y的所有者可以標記工程Z作為一個可選依賴, 使用optional標簽. 當工程X依賴工程Y時, X將只依賴Y, 而不依賴Z. X的所有者也可顯式地添加Z作為一個依賴. 這有助于將可選依賴理解為默認的排除依賴.
Dependency Scope
依賴范圍用于限制一個依賴的傳遞性, 也用于影響各種構建任務使用到的類路徑classpath.
有6種可用范圍:
(1) compile. 編譯依賴范圍. 這是默認的范圍, 如果沒有指定范圍, 默認使用之. 在一個工程的所有類路徑中, 編譯依賴都有效. 包括:編譯, 測試, 運行三種classpath.?? 此外, 這些依賴會擴散至依賴項目中.
典型例子: spring-core, 在編譯\測試\運行時都需要這種依賴.
(2) provide. 已提供依賴范圍. 與編譯依賴范圍很像, 但意味著你期望JDK或者一個容器來提供運行時依賴.? 例如, 當構建一個JAVA企業級的WEB應用時, 你將設置基于servlet api和相關的java ee api的provide依賴, 但在運行項目時, 因為web容器提供這些類, 就不需要maven重復地引入了.. 這個范圍只對編譯和測試classpath有效, 且不會傳遞.
典型例子: servlet-api, 在運行項目時由容器提供.
(3) runtime. 運行時依賴范圍. 這種范圍在編譯期不需要, 而運行時需要. 在運行和測試classpath中生效, 而編譯classpath不生效.
典型例子: JDBC驅動的實現. 項目主代碼的編譯只需要JDK提供的JDBC接口, 在執行測試或運行時才需要具體實現.
(4) test. 測試依賴范圍. 應用的正常使用時不需要, 只在測試時的編譯和運行階段生效.
典型例子: JUnit, 只有在編譯測試代碼和運行測試時才需要.
(5) system. 系統依賴范圍. 類似于provided, 期望由你來顯式提供JAR. 構件總是有效的, 而不需要去倉庫中查找. 通過 systemPath元素來顯式指定依賴文件的路徑, 可以引用環境變量. 不需要maven倉庫解析, 往往與本機系統綁定, 可能造成構建的不可移植, 謹慎使用.
(6) import. 導入依賴范圍. (only available in Maven 2.0.9 or later) 只用于依賴是一個POM時.? 指定的POM應該被當前工程的POM文件中的<dependencyManagement>節中定義的依賴關系取代. 因為他們被替代了, import依賴不會影響一個依賴的傳遞性. 也就是說, 對3種classpath沒有實際影響.
每一種范圍, 除了import, 以不同的方式影響著依賴傳遞性. 如下表所示.
Dependency Management
依賴管理部分是集中了依賴信息的機制. 當你有一組繼承自同一父工程的子工程時, 可以把所有依賴信息都放到共同POM中, 而在子POM中簡單地引用這些工程.
但存在一個問題: 依賴是會被繼承的. 我們可以確定多個子模塊中可能包含了若干依賴, 但無法確定某個子模塊一定需要全部的依賴.
maven提供的 dependency management元素 既讓子模塊依賴父模塊的配置, 又能保證子模塊依賴使用的靈活性. 在dependencyManagement元素下的依賴聲明不會引入實際的依賴, 不過它能約束 dependencies下的依賴使用.
(1) 將完整的依賴聲明包含在父POM中, 子模塊只需要配置簡單的groupId和artifactId就能獲得對應的依賴信息. 引入正確的依賴.
好處: 父POM中使用dependencyManagement聲明依賴能夠統一項目范圍中依賴的版本, 當依賴版本在父POM聲明之后, 子模塊就無須聲明 , 也不會發生多個子模塊中版本不一致的情況. 有助于降低依賴沖突的幾率.
注意, 如果子模塊不聲明依賴的使用, 即使該依賴聲明在父POM的dependencyManagement中, 也不會產生任何實際效果. ---靈活性.
給出2個POM, 它們繼承自同一父工程.
這兩個示例POM共享了一個共同的依賴, group-a:artifact-b:1.0.
上述工程的依賴可以合并到父POM中, 然后這兩個子POM就可以簡化:
注意: 在這些依賴引用中, 要特別指定<type>元素. 因為, 從dependencyManagement部分匹配一個依賴引用 的最小信息集實際上是:{groupId, artifactId, type, classifier}. 在很多情況下,如果沒有指定的話, 這些依賴將指向jar構件.
因為默認的type是jar, 而classifier是null, 所以我們可以使用 {groupId, artifactId} 作為標識的最小集合. 當type不是jar時, 需要特別指出.
(2) 在依賴傳遞中控制構件的版本.
上例中, project B繼承自project A.
dependency標簽會被自動繼承,? 而dependencyManagement標簽不會.
在子項目中的dependency中引入a, c 時, 可以指定版本和范圍, 由于依賴調解, 會覆蓋父POM中的定義.
注意, b 在父項目中定義了, 如果它在a, c中的pom中被引用的話, 就會使用該定義.
而d 在子項目中的dependencyManagement中定義的, 如果d 在a或c中引用 , 那就會使用這個定義, 因為依賴管理優先于依賴調解, 也因為當前pom的聲明優先于父pom的聲明.
Importing Dependencies
The features defined in this section are only available in Maven 2.0.9 or later.
前面提到的import依賴范圍只有在dependencyManagement元素下才有效果. 使用該范圍的依賴通常指向一個POM, 作用是將目標POM中的dependencyManagement配置導入并合并到當前POM的dependencyManagement元素中.
上圖中的project B與前一節中的示例的區別在于, 本例沒有繼承工程A, 而是通過import依賴范圍, 在dependencyManagement部分導入工程A中的dependencyManagement內容, 除了d以外. 因為在本例的dependencyManagement中也有定義了d.
上例中, Z導入了X,Y的依賴管理. 注意到X和Y都有依賴a, 且兩者的版本不同. 這里將使用X中的版本, 因為X是先定義的, 并且Z中沒有定義a.
import是非常有效的, 當用于定義一個多項目構建的相關構件庫時. 一個工程使用一個或多個這些庫里的構件是非常常見的. 然而,有時很難保持工程中使用的構件版本同步. 因為版本號分布在整個庫中. 下面的模式闡述了 一個BOM如何創建并用于其他工程.
工程的根是BOM pom. 它定義了所有構件的版本號. 其他使用了該庫的工程應該在它們自己的POM的dependencyManagement部分中導入.
?
父子工程使用BOM pom作為它的父親. 它是一個正常的復合pom.
\
實際的項目pom:
下面的工程演示了如何在其他項目中使用上述庫, 而不需要指定依賴工程的版本號:
注意:
不要試圖導入一個定義在當前POM中的子模塊的POM. 這樣將會導致構建失敗, 因為它無法定位該POM.
不要將導入的POM聲明為父或祖父POM. 無法處理循環, 將會拋出一個異常.
當引用的構件所屬的POM存在依賴傳遞時, 該工程需要在依賴管理中指定版本號. 如果不這樣做, 將導致 一個構建失敗, 因為構件可能沒有指定的版本號. 這應該視為一個最佳實踐, 在任何情況下. 因為它保證了構件的版本變來變去的.
System Dependencies
范圍為 system 的依賴, 總是有效的, 不需要到倉庫中搜索. 它們通常用于告訴maven, 哪些依賴由jdk 或vm提供. 典型應用是JDBC標準擴展, 或JAAS.
?
Reference
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies
<Maven實戰>
轉載于:https://www.cnblogs.com/lddbupt/p/5537137.html
總結
以上是生活随笔為你收集整理的Maven-Dependency Mechanism的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kinect V2 基础教程之彩色图像
- 下一篇: Struts拦截器使用