前兩天在一個技術羣,有人還在問maven中groupId、artifactId、version這些關鍵字的含義是什麼,因而,我以爲仍是頗有必要來聊聊Maven中的這些核心概念。java
成功不是未來纔有的,而是從決定去作的那一刻起,持續累積而成。web
今天咱們來學習Maven中的核心概念。瞭解了這些核心概念後,咱們後面就能夠更深層次的學習和使用Maven。面試
來自百度百科spring
可以肯定一個點在空間的位置的一個或一組數,叫作這個點的座標。一般由這個點到垂直相交的若干條固定的直線的距離來表示 。這些直線叫作座標軸。座標軸的數目在平面上爲2(x,y),在空間裏爲3(x,y,z)。
其實就是能夠標識平面中或空間裏惟一的一個點。apache
Maven其中一個核心的做用就是管理項目的依賴,引入咱們所需的各類jar包等。爲了能自動化的解析任何一個Java構件,Maven必須將這些Jar包或者其餘資源進行惟一標識,這是管理項目的依賴的基礎,也就是咱們要說的座標。包括咱們本身開發的項目,也是要經過座標進行惟一標識的,這樣才能才其它項目中進行依賴引用。api
依賴時候:好比下面咱們依賴junit的jar包。springboot
<!-- pom.xml中 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
項目中定義咱們的項目將打成jar或者war包。網絡
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tian</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 默認是jar -->
<packaging>jar</packaging>
</project>
最後打出來的jar或war的形式的形式:maven
artifactid-version.jar
artifactid-version.war
packaging 標籤默認是jar,因此一般咱們在沒有指定打成jar包仍是war的時候,最終打成的就是jar包。ide
「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」項目的當前版本或者咱們要依賴jar的版本。該元素定義了使用構件的版本,如上例中junit的版本是3.8.1,你也能夠改成4.0表示使用4.0版本的junit。
「packaging」項目的打包方式,最爲常見的jar和war兩種,默認是jar。定義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是不能直接定義的,須要結合插件使用。
依賴一般表現爲:我須要你的東西,就像情侶之間相互依賴,夫妻之間相互依賴,人依賴於水,人依賴於糧食等。
在Maven中則表現爲:項目中用到b.jar包的每一個類,此時的項目就依賴b.jar。
複雜點關係就是多層依賴:a.jar包依賴b.jar包,還有可能b.jar包依賴c.jar。這種現象也能夠稱之爲依賴傳遞性。
咱們的項目間接性的依賴了b.jar。
Maven中依賴配置案例以下:
<!--添加依賴配置-->
<dependencies>
<!--項目要使用到junit的jar包,因此在這裏添加junit的jar包的依賴-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<!--項目要使用到Hello的jar包,因此在這裏添加Hello的jar包的依賴-->
<dependency>
<groupId>com.tian.maven</groupId>
<artifactId>user-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope><!-- 依賴範圍-->
</dependency>
</dependencies>
所謂的依賴範圍就是指咱們在什麼須要依賴的jar。有的是在編譯的時候就須要,有的是測試的時候須要等。
依賴範圍scope有如下6種:
「compile」 默認編譯依賴範圍。對於編譯,測試,運行三種classpath都有效。即在編譯、測試和運行的時候都要使用該依賴jar包;
「test」測試依賴範圍。只對於測試classpath有效。而在編譯和運行項目時沒法使用此類依賴,典型的是JUnit,它只用於編譯測試代碼和運行測試代碼的時候才須要;
「provided」已提供依賴範圍。對於編譯,測試的classpath都有效,但對於運行無效。由於由容器已經提供,例如servlet-api.jar,這個在編譯和測試的時候須要用到,可是在運行的時候,web容器已經提供了,就不須要maven幫忙引入了。
「runtime」運行時依賴範圍,使用此依賴範圍的maven依賴,對於編譯測試、運行測試和運行項目的classpath有效,但在編譯主代碼時無效,好比jdbc驅動實現,運行的時候才須要具體的jdbc驅動實現。
「system」系統依賴範圍,使用system範圍的依賴時必須經過systemPath元素顯示地指定依賴文件的路徑,不依賴Maven倉庫解析,因此可能會形成建構的不可移植(即就是在你的電腦上可能沒問題,可是到別人電腦上那就說不清楚了),有點相似provided ,注意這個system謹慎使用。
<systemPath>${java.home}/lib/rt.jar</systemPath>
「import」僅pom在本節中的類型依賴項上支持此做用域。它指示依賴關係將被指定的pom部分中的有效依賴關係列表替換。因爲已替換它們,所以範圍爲的依賴項import實際上不會參與限制依賴項的可傳遞性,在springboot和springcloud中用到的比較多。
以上六種範圍中,經常使用的有compile、test、runtime、provided 。
依賴範圍不只能夠控制與三種classpath的關係,還對傳遞性依賴產生影響,依賴關係圖以下:
「注意」預期這應該是運行時範圍,所以必須明確列出全部編譯依賴項。可是,若是您依賴的庫從另外一個庫擴展了一個類,則二者都必須在編譯時可用。所以,即便編譯時間相關性是可傳遞的,它們仍保留爲編譯範圍。
用來統一存儲全部Maven共享構建的位置,說白了就是用來存放jar包的,咱們本地每次編譯的時候沒有對應jar包是編譯通不過的,咱們一個項目中是須要不少jar的依賴的,這時候就知道倉庫的重要性了。
根據Maven座標定義每一個構建在倉庫中惟一存儲路徑,大體爲:
groupId/artifactId/version/artifactId-version.packaging
在上一篇文章中,每一個用戶只有一個本地倉庫,默認是在~/.m2/repository/,~表明的是用戶目錄 。爲了便於管理,通常都會本身搞一目錄,專門用來存儲本地倉庫內容。這樣咱們開發的時候,依賴那個jar就直接去咱們的本地倉庫repository中去查找,若是沒有,咱們會從中央倉庫中拉取。
基本上保存了對外開發的全部jar包,Maven默認的遠程倉庫,(外國網站)URL地址:http://search.maven.org/ 。還有好比阿里的倉庫,咱們在開發的時候,因爲網絡緣由,不少人都喜歡使用阿里的這個倉庫:http://maven.aliyun.com 。
這時候咱們本地倉庫和中央倉庫的關係:
大部分公司都會搭建私服,私服就是一種特殊的遠程倉庫,它是架設在局域網內的倉庫 。好比公司搭建局域網,公司也搞個倉庫,而後開發人員就直接使用公司搭建的私服就好了,這樣大大減小了網絡開銷以及開發成本(有時候外網訪問很慢,會浪費你們開發時間的)。
這樣開發人員每次須要每一個jar包就直接從公司的私服里拉取,不須要使用外網去中央倉庫里拉取了。總之節約時間和節約網絡開始。而且有些企業仍是不給外網的,這時候你就知道這個私服的重要性了。
增長了私服後,本地倉庫+私服+中央倉庫的關係圖:
面試中也頻繁被問:本地倉庫、私服以及中央倉庫是什麼關係?
Maven的 生命週期:從咱們的項目構建,一直到項目發佈的這個過程。
每一個階段的說明:
爲了完成 default 生命週期,這些階段(包括其餘未在上面羅列的生命週期階段)將被按順序地執行。
Maven 有如下三個標準的生命週期:
這三個標準它們是相互獨立的,你能夠僅僅調用clean來清理工做目錄,僅僅調用site來生成站點。固然你也能夠直接運行 mvn clean install site運行全部這三套生命週期。
運行任何一個階段的時候,它前面的全部階段都會被運行,這也就是爲何咱們運行mvn install 的時候,代碼會被編譯,測試,打包。此外,Maven的插件機制是徹底依賴Maven的生命週期的,所以理解生命週期相當重要。
Maven是不作具體事情的,只是規定了生命週期的各個階段和步驟,由集成到 Maven 中的插件完成。
關於插件,這裏就說個大概,後續會出一篇文章專門來講Maven插件。
排除不須要依賴
<dependency>
<groupId>com.tian.maven</groupId>
<artifactId>my-maven</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>com.tian.maven</groupId>
<artifactId>your-maven</artifactId>
</exclusion>
</exclusions>
</dependency>
上面使用使用exclusions元素排除了my-maven->your-maven依賴的傳遞,也就是my-maven->your-maven不會被傳遞到當前項目中。
exclusions中能夠有多個exclusion元素,能夠排除一個或者多個依賴的傳遞,聲明exclusion時只須要寫上groupId、artifactId就能夠了,version能夠省略。
本文講述Maven座標,Maven依賴管理、Maven倉庫管理、Maven生命週期以及簡單介紹了Maven插件。有了這些概念做爲鋪墊,咱們就能夠更深層次去體會,爲何咱們在工做室這麼用的。
「只要路是對的,就不怕路遠。」