maven依賴管理
maven依賴說明
Maven的依賴管理十分強大,單個項目的依賴管理非常簡單,但是,當應用由多個模塊組成,並且應用有數十到數百個模塊組成時,依賴管理變得非常困難。此時,maven可以保證高度的依賴控制和穩定
maven的項目依賴主要配置在項目pom.xml的dependencies
節點中。依賴是使用Maven座標來定位的,因此,使用任何一個依賴之間,你都需要知道它的Maven座標。
在maven組件搜索網站上,每個組件都有maven依賴的配置內容,只需要將內容複製到項目pom.xml中的dependencies
節點即可。
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
完整的依賴節點包含以下節點:
groupId,必選,實際隸屬項目
artifactId,必選,其中的模塊
version必選,版本號
type可選,依賴類型,默認jar
scope可選,依賴作用域,默認compile
optional可選,標記依賴是否可選,默認false
exclusion可選,排除傳遞依賴性,默認空
上面的示例是編寫文檔時,junit的maven依賴。
依賴傳遞
依賴傳遞是maven2.0的新特徵。用於避免手動發現和添加需要的組件的依賴組件,maven會自動添加。
這個新特殊通過從遠程倉庫讀取項目依賴的工程文件實現,一般而言,組件的傳遞性依賴包括繼承自父項目的依賴組件,以及組件依賴的組件,等等。
因爲沒有限制依賴關係的層次。所以會產生一個問題:循環依賴(後面會有解決辦法)
因爲依賴傳遞,包含庫可能會快速增長,出於這個原因,一些特徵將用於限制依賴關係。
依賴調解
當遇到一個組件的多個版本依賴時,通過依賴調解決定使用哪個版本的組件。 maven2.0只支持“就近原則”,即選擇離依賴樹中最近一個版本。當然,你也可以選擇顯示的在項目pom文件中指定一個版本。 在maven2.0.9版本及之後的版本中,如果兩個版本的組件在項目依賴樹的在同一深度,那麼哪個依賴先聲明,用哪個版本。
舉例說明:
在項目A中,依賴B與C組件,B組件依賴D1.0與E1.0,而組件C依賴於F與E2.0,F依賴與D2.0。此時,產生了依賴衝突,即對組件D和組件E的依賴。此時,因爲組件D1.0更靠近項目,所以使用組件D1.0,對於E組件,因爲距離項目的距離相同,所以POM中組件B與C在誰先聲明,就用誰的依賴版本。
如果在POM中顯示的聲明D與E的版本,則使用指定版本。
依賴管理
即允許開發者在遇到傳遞性依賴,直接指定組件版本。
依賴作用域
見下節
依賴排除
假設X組件依賴於Y組件,Y組件依賴於Z組件,在引用X時,可以使用exclusion
節點,排隊項目對Z組件的引用。這常常用於解除依賴調解的“就近原則” ,使用離項目較遠的版本。
可選依賴
假設組件Y依賴於組件Z,在組件Y中可以通過optional
節點將Z定義爲可選依賴。X引用Y組件依賴時,Z組件將不參與依賴傳遞。X組件可以選擇性的顯示引用Z組件。
maven依賴作用域
scope節點表示依賴作用域。
依賴作用域是用來限制依賴關係的傳遞性,同時影響各類組件的作用域。
maven依賴有以下幾種:
compile
此作用域這是默認的作用域,如果依賴沒的指定作用域,則使用此作用域。此依賴作用域的依賴可用於項目的所有類路徑。此外,此依賴作用域參與依賴傳遞。
provided
此作用域和compile很像,只是在運行時此依賴由JDK或者容器提供。舉個例子,當構建一個J2EE web應用時,你就要將Servlet API和Java EE API的依賴作用域設置爲provided,因爲容器提供了這些類。此依賴作用域只作用於編譯和測試的類路徑。不參與依賴傳遞
runtime
此作用域表示依賴在編譯時不需要,但是執行時需要,作用於運行和測試時,但是不在編譯的類路徑中。
test
此作用域表示依賴在項目一般使用中不需要,只在測試編譯和測試執行期間使用。
system
此作用域與provided作用域相似,只是你必須提供顯示包含的jar。組件必須可用,maven不會在repository裏查找組件。
import(只在Maven 2.0.9及以後的版本中可用)
此作用域只用於pom依賴,主要是用來導入另一個POM中 dependency management 裏聲明的依賴仲裁。
每個不同的作用域以不同的方式影響依賴傳遞。如下表所示: 如果一個項目依賴設置爲左列的作用域,本依賴的傳遞依賴的作用域爲第一行的值,那麼傳遞依賴作用於本項目的的作用域將取交叉單元格的值,未列出的作用域,將被忽略
compile | provided | runtime | test | |
compile | compile(*) | - | runtime | - |
provided | provided | - | provided | - |
runtime | runtime | - | runtime | - |
test | test | - | test | - |
system作用域
system作用域的依賴組件應該總是可用,maven用不會去倉庫中查找,system作用域通常用於告訴 maven 由JDK與虛擬機提供的依賴。如果你將一個依賴範圍設置成系統範圍,你必須同時提供一個 systemPath 元素。注意該範圍是不推薦使用的
經典的使用例子就是JDBC標準擴展,Java身份驗證和授權服務(JAAS)。
<project> ... <dependencies> <dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jar</systemPath> </dependency> </dependencies> ... </project>
如果你的組件由JDK的tools.jar提供,系統路徑應如下定義:
<project> ... <dependencies> <dependency> <groupId>sun.jdk</groupId> <artifactId>tools</artifactId> <version>1.5.0</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> </dependencies> ... </project>
可選依賴
使用可選依賴的場景:一個項目A依賴於B,但是引用A的項目可能並不需要B,此時,A項目對B項目的依賴就可以配置成可選依賴,如果引用A的項目需要使用B的功能,可以手動引用B的依賴。
爲什麼使用可選依賴? 1. 節約磁盤、內存等空間; 1. 避免license許可問題; 1. 避免類路徑問題,等等。
<project> ... <dependencies> <!-- declare the dependency to be set as optional --> <dependency> <groupId>sample.ProjectA</groupId> <artifactId>Project-A</artifactId> <version>1.0</version> <scope>compile</scope> <optional>true</optional> <!-- value will be true or false only --> </dependency> </dependencies> </project>
配置可靠依賴只需要在dependency節點中添加true即可。
依賴排除
依賴排除的使用場景:當一個項目A依賴項目B,而項目B同時依賴項目C,如果項目A中因爲各種原因不想引用項目C,在配置項目B的依賴時,可以排除對C的依賴。
<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>
配置依賴排除時,只需要在節點dependency
添加exclusions
節點,在exclusions
節點中添加一個或者多個exclusion
即可。exclusion
節點包含groupId
與artifactId
節點,用於定義排隊的組件。
多重依賴
Demo:
對於如下依賴結構:
Project-A -> Project-B -> Project-D -> Project-E -> Project-F -> Project C
A對於E相當於有多重依賴,如果想在項目A中排除對E的依賴,只需要在配置B的依賴中進行即可:
<project> <modelVersion>4.0.0</modelVersion> <groupId>sample.ProjectA</groupId> <artifactId>Project-A</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> ... <dependencies> <dependency> <groupId>sample.ProjectB</groupId> <artifactId>Project-B</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>sample.ProjectE</groupId> <!-- Exclude Project-E from Project-B --> <artifactId>Project-E</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </project>
maven處理循環依賴
循環依賴
如果工程A依賴工程B,工程B又依賴工程A,就會形成循環依賴。或者A依賴B,B依賴C,C依賴A,也是循環依賴,總的來說,在畫出工程依賴圖之後,如果發現工程間的依賴連線形成了一個有向循環圖,則說明有循環依賴的現象。
解決循環依賴
第一個辦法是用build-helper-maven-plugin插件來規避。比如A依賴B,B依賴C,C依賴A的情況。這個插件提供了一種規避措施,即臨時地將工程A、B、C合併成一箇中間工程,編譯出臨時的模塊D。然後A、B、C再分別依賴臨時模塊D進行編譯
第二個辦法是通過重構
重構的思路
第一個思路是平移重構,例如項目A和B互相依賴,那麼可以將B依賴A的那部分平移到工程B中,或者將A依賴B的部分平移到A項目中,這樣就能消除循環依賴。 第二個思路應對如下情況,比如A和B互相依賴,同時它們都依賴C,那麼可以將B和A相互依賴的那部分移動到工程C裏,這樣一來,A和B相互之間都不依賴,只繼續依賴C,也可以消除循環依賴。