Maven(1)--坐标与依赖
坐標詳解
Maven通過坐標唯一標識一個組件。Maven坐標是通過groupId、artifactId、version、packaging、classfier這些元素來定義的。
<groupId>com.demon.study</groupId><artifactId>log4jtest</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging>?
- groupId
定義當前Maven項目隸屬的實際項目。首先,Maven項目和實際項目不一定是一對一的關系。比如SpringFrameWork這一實際項目,其對應的Maven項目會有很多,如spring-core,spring-context等。這是由于Maven中模塊的概念,因此,一個實際項目往往會被劃分成很多模塊。其次,groupId不應該對應項目隸屬的組織或公司。原因很簡單,一個組織下會有很多實際項目,如果groupId只定義到組織級別,而后面我們會看到,artifactId只能定義Maven項目(模塊),那么實際項目這個層次將難以定義。最后,groupId的表示方式與Java包名的表達方式類似,通常與域名反向一一對應。上例中,groupId為junit,是不是感覺很特殊,這樣也是可以的,因為全世界就這么個junit,它也沒有很多分支。
- artifactId
該元素定義當前實際項目中的一個Maven項目(模塊),推薦的做法是使用實際項目名稱作為artifactId的前綴。比如上例中的junit,junit就是實際的項目名稱,方便而且直觀。在默認情況下,maven生成的構件,會以artifactId作為文件頭,如junit-3.8.1.jar,使用實際項目名稱作為前綴,就能方便的從本地倉庫找到某個項目的構件。
- version
該元素定義了使用構件的版本,如上例中junit的版本是3.8.1,你也可以改為4.0表示使用4.0版本的junit。
- packaging
定義Maven項目打包的方式,使用構件的什么包。首先,打包方式通常與所生成構件的文件擴展名對應,如上例中沒有packaging,則默認為jar包,最終的文件名為junit-3.8.1.jar。也可以打包成war等。
- classifier
該元素用來幫助定義構建輸出的一些附件。附屬構件與主構件對應,如上例中的主構件為junit-3.8.1.jar,該項目可能還會通過一些插件生成如junit-3.8.1-javadoc.jar,junit-3.8.1-sources.jar, 這樣附屬構件也就擁有了自己唯一的坐標。
上述5個元素中,groupId、artifactId、version是必須定義的,packaging是可選的(默認為jar),而classfier是不能直接定義的,需要結合插件使用。
依賴
依賴配置
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version><scope>test</scope> </dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.11.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.11.1</version></dependency></dependencies>?dependencies可以包含一個或多個dependency。
包含元素有:
- groupId
- artifactId
- version
- type:依賴的類型。對應于項目坐標定義的packaging。大部分情況下,不必聲明,默認為jar。
- classifier:依賴的分類器。分類器可以區分屬于同一個POM,但不同構建方式的構件。分類器名被附加到文件名的版本號后面。例如,如果你想要構建兩個單獨的構件成 JAR,一個使用Java 1.4編譯器,另一個使用Java 6編譯器,你就可以使用分類器來生成兩個單獨的JAR構件。
- scope:依賴范圍。在項目發布過程中,幫助決定哪些構件被包括進來
- systemPath:僅供system范圍使用。注意,不鼓勵使用這個元素,并且在新的版本中該元素可能被覆蓋掉。該元素為依賴規定了文件系統上的路徑。需要絕對路徑而不是相對路徑。推薦使用屬性匹配絕對路徑,例如${java.home}。
- optional:可選依賴(true/false),如果你在項目B中把C依賴聲明為可選,你就需要在依賴于B的項目(例如項目A)中顯式的引用對C的依賴。可選依賴阻斷依賴的傳遞性
- exclusions:用來排除傳遞性依賴。
依賴范圍
依賴范圍用來控制依賴與三種classpath(編譯classpath,測試classpath,運行classpath)之間的關系。
maven有以下幾種依賴:
- compile :編譯依賴范圍。如果沒有指定,默認使用此范圍。對編譯,測試,運行都有效。典型例子spring-core。
- provided:以提供依賴范圍。僅對編譯和測試有效。運行時無效。典型例子:servlet-api,運行時由容器提供。
- runtime: 運行時依賴范圍。只在測試或運行時有效。編譯時無效。典型例子JDBC,
- test: 測試依賴范圍。只對測試classpath有效。典型例子junit。
- system: 系統依賴范圍。與classpath的關系與provided一致。但是必須通過systemPath來指定依賴文件的路徑
- import:導入依賴范圍。不會對classpath產生影響。參考:
| compile | Y | Y | Y | spring-core |
| provided | Y | Y | N | servlet-api |
| runtime | N | Y | Y | JDBC |
| test | N | Y | N | junit |
| system | Y | Y | N | 本地文件。 |
?傳遞性依賴
依賴的傳遞性是指:在A 中添加對B 的依賴,在B 中添加對C 的依賴,如果依賴范圍是compile 的,A 不僅會有B 的jar 包,也會有C 的jar 包。如果在C 中添加了某個依賴,那么根據傳遞性,A 和B 也可以使用C添加的依賴,而不需要自己再重新引入依賴。
?
傳遞性依賴與依賴范圍
依賴范圍不僅可以控制與3種classpath的關系,還對傳遞性依賴產生影響。
假設A依賴于B,B依賴于C,我們說A對于B是第一直接依賴,B對于C第二直接依賴,A對于C的傳遞性依賴。第一依賴的范圍和第二依賴的范圍決定了傳遞性的依賴范圍。
| ??? \\\\\\\\\\????? 第二依賴 ??????????? \\\\\\\\\\ 第一依賴????? \\\\\\\\\\\\ | compile | test | provided | runtime |
| compile | compile | --- | --- | runtime |
| test | test | --- | --- | test |
| provided | provided | --- | provided | provided |
| runtime | runtime | --- | --- | runtime |
- 當第二直接依賴是compile范圍時。傳遞性依賴范圍與第一直接依賴相同。
- 當第二直接依賴是test范圍時。依賴不傳遞。
- 當第二直接依賴是provided范圍時。只傳遞provided依賴,并且傳遞依賴為provided。
- 當第二直接依賴是runtime范圍時。傳遞性依賴范圍與第一直接依賴相同。但compile會傳遞為runtime
依賴調解
?針對于傳遞性依賴造成問題的時候,我們需要清楚知道傳遞性依賴的從哪條路徑引入的。例如A->B-C->X(1.0)? A->D
->X(2.0),兩條路徑有兩個版本的X,兩個版本都被解析是不對的,因為會造成依賴重復,因此必須選擇一個。maven依賴調解(Dependency Mediation)
第一條原則是:路徑最近者優先。因此X(2.0)會被解析使用。
當路徑相同時我們采取
第二條原則,第一聲明者優先。即誰在pom文件中先聲明,先被解析。
可選依賴
假設A->B ,B->X(可選),B->Y(可選)。如果都是compile范圍,則X,Y是A的傳遞性compile范圍。但是由于X,Y是可選的,則依賴不會傳遞,即X,Y對A沒有任何影響。
為什么要使用可選依賴呢?假設項目B實現了2個特性,特性一依賴于X,特性二依賴于Y,但是X與Y互斥,例如B是持久層工具包,支持oracle,mysql等,構建項目時,只需要其中的一個。則A需要顯示聲明X或Y依賴。
依賴排除
在依賴傳遞過程中,如A依賴B、S2.0,B依賴C、S1.0,這樣A就有了S1.0和S2.0兩個依賴,這樣某些情況下會造成沖突需要手動把B間接傳遞過來的依賴排除掉,就是不依賴B帶過來的S1.0的包。
我們在當前工程中引入了A 的依賴,而A 同時有對B 的依賴,根據傳遞性我們知道,在當前工程中會自動引入對B 的依賴。其中B 可能是一個不穩定的版本,或者對當前的工程存在著不良的影響 。這時我們就可以在引入對A 依賴的同時排除對B 的依賴。
使用exclusion來進行排除
<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>?
?
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的Maven(1)--坐标与依赖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring--SPeL
- 下一篇: 架构师知识地图