1. 程式人生 > 實用技巧 >五分鐘快速掌握Maven的核心概念

五分鐘快速掌握Maven的核心概念

前兩天在一個技術群,有人還在問maven中groupId、artifactId、version這些關鍵字的含義是什麼,於是,我覺得還是很有必要來聊聊Maven中的這些核心概念。

成功不是將來才有的,而是從決定去做的那一刻起,持續累積而成。

今天我們來學習Maven中的核心概念。瞭解了這些核心概念後,我們後面就可以更深層次的學習和使用Maven。

座標

座標的概念

來自百度百科

能夠確定一個點在空間的位置的一個或一組數,叫做這個點的座標。通常由這個點到垂直相交的若干條固定的直線的距離來表示 。這些直線叫做座標軸。座標軸的數目在平面上為2(x,y),在空間裡為3(x,y,z)。

其實就是可以標識平面中或空間裡唯一的一個點。

Maven中的座標

Maven其中一個核心的作用就是管理專案的依賴,引入我們所需的各種jar包等。為了能自動化的解析任何一個Java構件,Maven必須將這些Jar包或者其他資源進行唯一標識,這是管理專案的依賴的基礎,也就是我們要說的座標。包括我們自己開發的專案,也是要通過座標進行唯一標識的,這樣才能才其它專案中進行依賴引用。

案例

依賴時候:比如下面我們依賴junit的jar包。

<!-- 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的形式的形式:

artifactid-version.jar
artifactid-version.war

packaging 標籤預設是jar,所以通常我們在沒有指定打成jar包還是war的時候,最終打成的就是jar包。

Maven座標的組成

「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為什麼使用座標呢?

  • Maven世界裡擁有大量構建,我們需要找一個用來唯一標識一個構建的統一規範。
  • 擁有了統一規範,就可以把查詢工作交給機器。

maven依賴管理

依賴

依賴通常表現為:我需要你的東西,就像情侶之間相互依賴,夫妻之間相互依賴,人依賴於水,人依賴於糧食等。

在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倉庫管理

Maven倉庫

用來統一儲存所有Maven共享構建的位置,說白了就是用來存放jar包的,我們本地每次編譯的時候沒有對應jar包是編譯通不過的,我們一個專案中是需要很多jar的依賴的,這時候就知道倉庫的重要性了。

Maven倉庫佈局

根據Maven座標定義每個構建在倉庫中唯一儲存路徑,大致為:

groupId/artifactId/version/artifactId-version.packaging

本地倉庫

在上一篇文章中,每個使用者只有一個本地倉庫,預設是在/.m2/repository/,代表的是使用者目錄 。為了便於管理,一般都會自己搞一目錄,專門用來儲存本地倉庫內容。這樣我們開發的時候,依賴那個jar就直接去我們的本地倉庫repository中去查詢,如果沒有,我們會從中央倉庫中拉取。

中央倉庫

基本上儲存了對外開發的所有jar包,Maven預設的遠端倉庫,(外國網站)URL地址:http://search.maven.org/ 。還有比如阿里的倉庫,我們在開發的時候,由於網路原因,很多人都喜歡使用阿里的這個倉庫:http://maven.aliyun.com

這時候我們本地倉庫和中央倉庫的關係:

私服

大部分公司都會搭建私服,私服就是一種特殊的遠端倉庫,它是架設在區域網內的倉庫 。比如公司搭建區域網,公司也搞個倉庫,然後開發人員就直接使用公司搭建的私服就行了,這樣大大減少了網路開銷以及開發成本(有時候外網訪問很慢,會浪費大家開發時間的)。

這樣開發人員每次需要每個jar包就直接從公司的私服里拉取,不需要使用外網去中央倉庫里拉取了。總之節約時間和節約網路開始。並且有些企業還是不給外網的,這時候你就知道這個私服的重要性了。

增加了私服後,本地倉庫+私服+中央倉庫的關係圖:

面試中也頻繁被問:本地倉庫、私服以及中央倉庫是什麼關係?

Maven生命週期

Maven的 生命週期:從我們的專案構建,一直到專案釋出的這個過程。

每個階段的說明:

為了完成 default 生命週期,這些階段(包括其他未在上面羅列的生命週期階段)將被按順序地執行。

Maven 有以下三個標準的生命週期:

  • Clean Lifecycle 在進行真正的構建之前進行一些清理工作。
  • Default Lifecycle 構建的核心部分,編譯,測試,打包,部署等等。
  • Site Lifecycle 生成專案報告,站點,釋出站點。

這三個標準它們是相互獨立的,你可以僅僅呼叫clean來清理工作目錄,僅僅呼叫site來生成站點。當然你也可以直接執行 mvn clean install site執行所有這三套生命週期。

執行任何一個階段的時候,它前面的所有階段都會被執行,這也就是為什麼我們執行mvn install 的時候,程式碼會被編譯,測試,打包。此外,Maven的外掛機制是完全依賴Maven的生命週期的,因此理解生命週期至關重要。

Maven外掛

Maven是不做具體事情的,只是規定了生命週期的各個階段和步驟,由整合到 Maven 中的外掛完成。

  1. Maven的核心僅僅定義了抽象的生命週期,具體的任務都是交由外掛完成的。
  2. 每個外掛都能實現多個功能,每個功能就是一個外掛目標。
  3. Maven的生命週期與外掛目標相互繫結,以完成某個具體的構建任務,
    例如compile就是外掛maven-compiler-plugin的一個外掛目標。

關於外掛,這裡就說個大概,後續會出一篇文章專門來說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外掛。有了這些概念作為鋪墊,我們就可以更深層次去體會,為什麼我們在工作室這麼用的。

「只要路是對的,就不要怕遠。」