基本工具之Maven

本篇介紹Maven,內容皆總結摘抄自《Maven實戰》,僅用作筆記。

Maven簡介

Maven是Apache組織中的一個頗爲成功的開源項目,主要服務於基於Java平臺的項目構建、依賴管理和項目信息管理。

Maven是一個異常強大的構建工具,能夠幫我們自動化構建過程,從清理、編譯、測試到生成報告,再到打包和部署。只需要使用Maven配置好項目,然後輸入命令即可。

Maven通過一個座標系統準確的定位每一個構件(artifact),也就是說通過一組座標Maven能夠找到任何一個Java類庫。

Maven還能幫助我們管理原本分散在項目中各個角落的項目信息,包括項目描述、開發者列表、版本控制系統地址等。

Maven還爲全世界的Java開發者提供了一個免費的中央倉庫,在其中幾乎可以找到任何的流行開源類庫。

安裝和配置

下載Maven

到Maven官網http://maven.apache.org/download.cgi選擇下載後綴爲bin.zip的文件,然後解壓。如下圖:

修改本地倉庫路徑

進入conf目錄,打開settings.xml,找到localRepository元素修改爲要設置爲本地倉庫的目錄,例如:

設置阿里雲鏡像

Maven默認訪問中央倉庫,而中央倉庫地址在國外,因此在下載構件時速度很慢。設置阿里雲鏡像可以有效解決這一問題。

進入conf目錄,打開settings.xml,在mirrors元素中添加以下mirror標籤:

 <mirror>  
     <id>alimaven</id>  
     <name>aliyun maven</name>  
     <url>http://maven.aliyun.com/nexus/content/groups/public/</url>  
     <mirrorOf>central</mirrorOf>          
 </mirror> 

設置環境變量

在桌面上右擊“我的電腦”->“屬性”,單擊”高級設置“,再選擇“環境變量”。在系統變量中添加一個變量,變量名爲MAVEN_HOME,變量值爲Maven的解壓目錄。如下圖:

然後在系統變量中找到名爲Path的變量,在變量值的末尾添加“%MAVEN_HOME%\bin;”,如下圖:

配置好環境變量後,打開cmd窗口,輸入“mvn -v”檢查Maven是否安裝成功。如下圖是安裝成功的。

安裝目錄分析

解壓之後的Maven目錄包含如下結構和內容:

  • bin:包含了mvn運行的腳本,這些腳本用來配置Java命令,準備好classpath和相關的Java系統屬性,然後執行Java命令。
  • boot:包含了plexus-classworlds-2.6.0.jar文件,plexus-classworlds是一個類加載器框架,相對於默認的java類加載器,它提供了更豐富的語法以方便配置,Maven使用該框架加載自己的類庫。
  • conf:包含了一個非常重要的文件settings.xml。直接修改該文件,就能在機器上全局的定製Maven的行爲。
  • lib:包含了所有Maven運行時需要的Java類庫。此外,還包含一些Maven用到的第三方依賴。可以說,lib目錄就是真正的Maven。

使用入門

Maven項目的核心是pom.xml。POM(Project Object Model,項目對象模型)定義了項目的基本信息,用於描述項目如何構建,聲明項目依賴等等。下面是一個最簡單的pom.xml。

<?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">
    <parent>
        <artifactId>project</artifactId>
        <groupId>org.galiden</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>module</artifactId>
    <name>module</name>
</project>

代碼的第一行是XML頭,指定了該xml文檔的版本和編碼方式。緊接着是project元組,project是所有pom.xml的根元素,它還聲明瞭一些POM相關的命名空間及xsd元素。

根元素下的modelVersion指定了當前POM模型的版本。

groupId、artifactId和version這三個元素定義了一個項目的基本座標。在Maven的世界,任何的jar、pom或者war都是基於這些基本的座標進行區分的。groupId定義了項目屬於哪個組,這個組往往和項目所在的組織或公司存在關聯。artifactId定義了當前Maven項目在族中唯一的ID。version指定了該項目當前的版本---1.0-SNAPSHOT,SNAPSHOT意爲快照,說明該項目還在開發中,是不穩定的版本。

最後一個name元素聲明瞭一個對於用戶更爲友好的項目名稱。

Maven項目中默認的主代碼目錄是src/main/java,對應的,默認的測試代碼目錄是src/test/java。

這篇文章中介紹了idea如何創建maven項目,我們就使用一個具有多個module的project做演示。其項目結構如下:

在項目根目錄下運行命令“mvn clean compile”會得到以下輸出:

clean告訴Maven清理輸出目錄target/,compile告訴Maben編譯項目主代碼。至此,Maven再沒有任何額外的配置的情況下就執行了項目的清理和編譯任務。

接下來調用Maven執行測試,在使用JUnit單元測試時,要添加JUnit依賴,修改項目的POM代碼如下:

<?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">
    <parent>
        <artifactId>project</artifactId>
        <groupId>org.galiden</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>module</artifactId>
    <name>module</name>
    <dependecies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependecies>
</project>

代碼中添加了dependencies元素,該元素下可以包含多個dependency元素以聲明項目的依賴。這裏添加了一個依賴---groupId是junit,artifactId是junit,version是4.12。有了這段聲明,Maven就會自動訪問中央倉庫,下載需要的文件。

上述POM代碼中還有一個值爲test的元素scope,scope爲依賴範圍,若依賴範圍爲test則表示該依賴只對測試有效。換句話說,測試代碼中的import JUnit是沒有問題的,但如果在主代碼中用import JUnit代碼,就會造成編譯錯誤。如果不聲明依賴範圍,默認值是compile,表示該依賴對主代碼和測試代碼都有效。

在項目根目錄執行命令“mvn clean test”。由下圖可以看出任務執行成功了。

將項目進行編譯、測試之後,下一個步驟就是打包。在項目根目錄執行命令“mvn clean package”進行打包,可以看到如下輸出:

類似的,Maven在打包之前執行編譯、測試等操作。打包其實就是jar插件的jar目標將項目主代碼打包成一個名爲module-1.0-SNAPSHOT.jar的文件。該文件也位於target/輸出目錄中。

至此,我們得到了項目的輸出,如果有需要的話,就可以複製這個jar文件到其他項目的Classpath中從而使用App類。但如果要讓其他的Maven項目直接引用這個jar包,還需要一個安裝步驟,執行命令“mvn clean install”安裝jar包。

該任務將項目輸出的jar安裝到了Maven本地倉庫中,只有將類的構件安裝到本地倉庫之後,其他Maven項目才能使用它。

使用Archetype生成項目骨架

在上面生成的Maven項目中有一些Maven的約定,例如在項目的根目錄中放置pom.xml,在src/main/java目錄中放置項目的主代碼,在src/test/java中放置項目的測試代碼。我們稱這些基本的目錄結構和pom.xml文件稱爲項目的骨架。

我們可以使用maven archetype來創建項目的骨架。事實上,上面例子中的project就是筆者在介紹idea時使用骨架創建的一個Maven項目。所以不需要手動創建pom.xml和src/main/java目錄以及src/test/java目錄結構。

座標和依賴

Maven的一大功能是管理項目依賴。爲了能自動化的解析任何一個Java構件,Maven就必須它們唯一標識。這就依賴管理的底層基礎---座標。

Maven的世界中擁有數量巨大的構件,也就是平時用的一些jar、war等文件。在Maven爲這些構件引入座標概念之前,我們無法使用任何一種方式來唯一標識所有這些構件。Maven定義了這樣一組規則:世界上任何一個構件都可以使用Maven座標唯一標識,Maven座標的元素包括groupId、artifactId、version、packaging、classifier。只要我們提供正確的座標元素,Maven就能找到對應的構件。

下面詳細解釋一下各個座標元素:

  • groupId:定義當前Maven項目隸屬的實際項目。Maven項目和實際項目不一定是一對一的關係,例如SpringFramework這一實際項目對應的Maven項目會有spring-core、spring-context等。這是由於Maven中模塊的概念,因此,一個實際項目往往會被劃分爲很多模塊。其次,groupId不應該對應項目隸屬的組織或公司,因爲一個組織下會有很多實際項目,如果groupId只定義到組織級別,由於artifactId只能定義Maven項目,那麼實際項目這個層將難以定義。
  • artifactId:定義實際項目中的一個Maven項目,推薦的做法是使用實際項目名稱作爲artifactId的前綴。
  • version:定義了Maven項目當前所處的版本。
  • packaging:定義Maven項目的打包方式。打包方式通常與所生成構件的文件擴展名對應,例如打包方式爲jar包,最終的文件名的後綴爲.jar。當不定義packaging的時候,Maven會使用默認值jar。
  • classifier:用來幫助定義構建輸出的一些附屬構件。

在上述5個元素中,groupId、artifactId和version是必須定義的,packaging是可選的,classifier是不可直接定義的。

根元素project下的dependencies可以包含一個或多個dependency元素,以聲明一個或多個項目依賴。每個依賴可以包含的元素有:

  • groupId、artiafactId和version:依賴的基本座標,對於任何一個依賴來說,基本座標是最重要的,Maven根據座標才能找到需要的依賴。
  • type:依賴的類型,對應於項目座標定義的packaging,默認值爲jar。
  • scope:依賴的範圍。
  • optional:標記依賴是否可選。
  • exclusions:用來排除傳遞性依賴。

倉庫

座標和依賴是任何一個構件在Maven世界中的邏輯表示方式;而構件的物理表示方式是文件,Maven通過倉庫來統一管理這些文件。

在Maven世界中,任何一個依賴、插件或項目構建的輸出,都可以稱爲構件。得益於座標機制,任何Maven項目使用任何一個構件的方式都是完全相同的。在此基礎上,Maven可以在某個位置統一存儲所有Maven項目共享的構件,這個統一的位置就是倉庫。實際的Maven項目將不再各自存儲其依賴文件,只需要聲明這些依賴的座標,在需要的時候,Maven會自動根據座標找到倉庫中的構件,並使用它們。

對於Maven來說,倉庫只分爲兩類:本地倉庫和遠程倉庫。當Maven根據座標尋找構件時,它首先會查看本地倉庫,如果本地倉庫存在此構件,則直接使用;否則,Maven就會去遠程倉庫查找,發現需要的構件之後,下載到本地倉庫再使用。如果本地倉庫和遠程倉庫都沒有需要的構件,就會報錯。

在這個最基本分類的基礎上,還有一些特殊的遠程倉庫。中央倉庫是Maven核心自帶的遠程倉庫,它包含了絕大部分開源的構件。在默認配置下,當本地倉庫沒有Maven需要的構件時,就會嘗試從中央倉庫下載。

私服是另一種特殊的遠程倉庫,爲了節省帶寬和時間,應該在局域網內架設一個私有的倉庫服務器,用其代理所有外部的遠程倉庫。

使用Maven進行日常開發時,一個常見的問題就是如何尋找需要的依賴,我們可能只知道需要使用類庫的項目名稱,但添加Maven依賴需要提供確切的Maven座標。這是可以使用倉庫搜索服務來根據關鍵字得到Maven座標。

筆者使用的是一個叫做Maven Repository的倉庫搜索服務,網址爲https://mvnrepository.com/。例如搜索junit的座標,如下圖:

選擇第2個之後如下圖:

我們可以根據使用次數來選擇相對來說可能更“穩定”的那個版本,選擇4.12版本後出現如下圖:

將紅框中的內容複製到pom.xml的dependencies元素中即可。

生命週期和插件

Maven的生命週期是爲了對所有的構建過程進行抽象和統一,包含了項目的清理、初始化、編譯、測試、打包、集成測試、驗證、部署和站點生成等幾乎所有構建步驟。也就是說,幾乎所有項目的構建,都能映射到這樣一個生命週期上。

Maven的生命週期是抽象的,這意味着生命週期本身不做任何實際的工作,在Maven的設計中,實際的任務都交由插件來完成。生命週期抽象了構建的各個步驟,定義了它們的次序,但沒有提供具體實現。因此Maven設計了插件機制,每個構建步驟都可以綁定一個或者多個插件行爲,而且Maven爲大多數構建步驟編寫並綁定了默認插件。

聚合與繼承

當Maven應用到實際項目中的時候,需要將項目分成不同的模塊。Maven的聚合特性能夠把項目的各個模塊聚合在一起構建,而Maven的繼承特性則能幫助抽取各模塊相同的依賴和插件配置,在簡化POM的同時,還能促進各個模塊配置的一致性。

聚合

當一個實際項目擁有多個Maven項目時,我們會想要一次構建多個項目,而不是到多個模塊的目錄下執行mvn命令。Maven聚合特性就是爲該需求服務的。

爲了使用一條命令就能構建多個模塊,我們需要創建一個額外的模塊A,然後通過該模塊構建整個項目的所有模塊。A本身作爲一個Maven項目,它必須要有自己的POM,但作爲一個聚合項目,其POM又有特殊的地方。其第一個特殊的地方在packaging元素,值爲pom。對於聚合模塊來說,其打包方式packaging的值必須爲pom,否則就無法構建。

實現聚合最核心的配置是module元素。用戶可以通過在一個打包方式爲pom的Maven項目中聲明任意數量的module元素來實現模塊的聚合。這裏的每個module的值都是一個當前POM的相對目錄。爲方便用戶構建項目,通常將聚合模塊放在項目目錄的最頂層,其他模塊作爲聚合模塊的子目錄存在。

繼承

在多模塊Maven項目中,他們的pom.xml可能會存在大量的重複,而重複往往就意味着更多的勞動和更多的潛在的問題。類似於面向對象設計中的父子結構,我們也可以創建POM的父子結構,然後在父POM中聲明一些配置供子POM繼承,以實現“一處聲明,多處使用”的目的。

作爲父模塊的POM,其打包類型也必須爲pom。另外,由於父模塊只是爲了幫助消除配置的重複,因此它本身不包含除POM之外的項目文件,也就不需要src/main/java之類的文件夾了。

有了父模塊,就需要讓其他模塊來繼承它。子模塊中增加parent元素來聲明父模塊,parent下的子元素groupId、artifactId和version指定了父模塊的座標,這三個元素是必須的。元素relativePath表示父模塊POM的相對路徑。在前面“使用入門”中舉例的project就是一個父模塊,而module是一個子模塊。project的POM的部分內容如下:

<groupId>org.galiden</groupId>
<artifactId>project</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
    <module>module</module>
</modules>
<name>project</name>

可以看出其packaging的值爲pom且包含一個子模塊module。而子模塊module的POM部分內容如下:

<parent>
    <artifactId>project</artifactId>
    <groupId>org.galiden</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>

聲明瞭其父模塊project的座標。

idea配置Maven

使用Ctrl + Alt + s或在上方菜單欄選擇File->Settings打開Settings,找到Maven,如下圖:

eclipse配置Maven

在上方菜單欄選擇Window->Preference,找到Maven->Installations,如下圖:

點擊Add,選擇要配置的Maven目錄,如下圖:

找到Maven->User Settings,如下圖:

設置完成後本地倉庫目錄修改爲之前在settings.xml文件中設置的目錄:

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章