maven install,build,package等各種基操及避坑指南

0 前言

全是乾貨的技術殿堂

文章收錄在我的 GitHub 倉庫,歡迎Star/fork:
Java-Interview-Tutorial
https://github.com/Wasabi1234/Java-Interview-Tutorial

1 是什麼

Apache的優秀開源項目
是Java項目的構建和管理工具

Maven 是 Apache 組織下的一個跨平臺的項目管理工具,它主要用來幫助實現項目的構建、測試、打包和部署。Maven 提供了標準的軟件生命週期模型和構建模型,通過配置就能對項目進行全面的管理。它的跨平臺性保證了在不同的操作系統上可以使用相同的命令來完成相應的任務。Maven 將構建的過程抽象成一個個的生命週期過程,在不同的階段使用不同的已實現插件來完成相應的實際工作,這種設計方法極大的避免了設計和腳本編碼的重複,極大的實現了複用。

2 能幹什麼

  1. 用maven方便的創建項目,基於archetype可以創建多種類型的java項目
  2. Maven倉庫對jar包(artifact)進行統一管理,避免jar文件的重複拷貝和版本衝突
  3. 團隊開發,管理項目的RELEASE和SNAPSHOT版本,方便多模塊(Module)項目的各模塊之間的快速集成
    簡介
    本文將介紹基於 Apache Maven 3 的項目構建的基本概念和方法。Maven 是一套標準的項目構建和管理工具,使用統一規範的腳本進行項目構建,簡單易用,摒棄了 Ant 中繁瑣的構建元素,並具有較高的可重用性。讀完本文,你將瞭解 Maven 的基本概念和使用它進行項目構建的基本方法。

Maven vs Ant

Ant 也是 Apache 組織下的一個跨平臺的項目構建工具,它是一個基於任務和依賴的構建系統,是過程式的。開發者需要顯示的指定每一個任務,每個任務包含一組由 XML 編碼的指令,必須在指令中明確告訴 Ant 源碼在哪裏,結果字節碼存儲在哪裏,如何將這些字節碼打包成 JAR 文件。Ant 沒有生命週期,你必須定義任務和任務之間的依賴,還需要手工定義任務的執行序列和邏輯關係。這就無形中造成了大量的代碼重複。

Maven 不僅是一個項目構建工具還是一個項目管理工具。它有約定的目錄結構(表 1)和生命週期,項目構建的各階段各任務都由插件實現,開發者只需遵照約定的目錄結構創建項目,再配置文件中生命項目的基本元素,Maven 就會按照順序完成整個構建過程。Maven 的這些特性在一定程度上大大減少了代碼的重複。

3 常用命令

maven install

maven的install可以將項目本身編譯並打包到本地倉庫,這樣其他項目引用本項目的jar包時不用去私服上下載jar包,直接從本地就可以拿到剛剛編譯打包好的項目的jar包,很靈活,避免每次都需要重新往私服發佈jar包的痛苦;

2,修改服務端比如manage層和dao層的項目的時候如果eclipse沒有自動編譯,則在調試的時候容易出很奇怪的錯誤,就是明明代碼已經改好了,但是debug的時候還是在報錯,這就是沒有項目沒有編譯完成造成的,看到的改好的代碼沒有變成class,因此,服務端的文件改動之後如果發現沒有效果的時候要記得問題可能是沒有編譯,這時候可以使用maven的install命令編譯一下;

idea可以很方便創建project和module,但是修改各個module的版本的時候,會遇到import報錯的情況,這就是maven倉庫中沒有對應的包,仍然需要使用到install,注意要使用lifecycle裏面的install,這樣就可以將已有的module打包到maven倉庫,再進行修改版本號,不會影響項目裏的其他module

mvn clean

編譯命令: mvn compile

打包命令: mvn package

跳過單元測試:mvn clean package -Dmaven.test.skip=true

4 避坑指南

  • 對於多模塊的項目,注意父 pom 會設置 JDK 版本,注意對齊版本號!

項目對象模型 POM

POM 即 Project Object Module,項目對象模型,在 pom.xml 文件中定義了項目的基本信息、源代碼、配置文件、開發者的信息和角色、問題追蹤系統、組織信息、項目授權、項目的 url、以及構建項目所用的插件,依賴繼承關係。開發人員需按照 maven 定義的規則進行 POM 文件的編寫

<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/maven-v4_0_0.xsd"> 
 <modelVersion>4.0.0</modelVersion> 
 <!  The Basics  > 
 <groupId></groupId> 
 <artifactId></artifactId> 
 <version></version> 
 <packaging></packaging> 
 <dependencies></dependencies> 
 <parent></parent> 
 <dependencyManagement></dependencyManagement> 
 <modules></modules> 
 <properties></properties> 
 <!  Build Settings  > 
 <build></build> 
 <reporting></reporting> 
 <!  More Project Information  > 
 <name></name> 
 <description></description> 
 <url></url> 
 <inceptionYear></inceptionYear> 
 <licenses></licenses> 
 <organization></organization> 
 <developers></developers> 
 <contributors></contributors> 
 <!  Environment Settings  > 
 <issueManagement></issueManagement> 
 <ciManagement></ciManagement> 
 <mailingLists></mailingLists> 
 <scm></scm> 
 <prerequisites></prerequisites> 
 <repositories></repositories> 
 <pluginRepositories></pluginRepositories> 
 <distributionManagement></distributionManagement> 
 <profiles></profiles> 
</project>

在每個 POM 文件中都含有的元素是該 project 的座標,它包含三個基本元素。

groupId 定義了項目屬於哪個組,這有助於在大的範圍上區別項目。artifactId 定義了這個項目在組中唯一的 ID。name 是一個用戶友好的項目名稱。

除了項目座標外,modelVersion 指定 POM 模型的版本,version 指明當前項目的版本,packaging 指定了項目發佈時的打包類型。

Maven 插件和倉庫

Maven 本質上是一個插件框架,它的核心並不執行任何具體的構建任務,僅僅定義了抽象的生命週期,所有這些任務都交給插件來完成的。每個插件都能完成至少一個任務,每個任務即是一個功能,將這些功能應用在構建過程的不同生命週期中。這樣既能保證拿來即用,又能保證 maven 本身的繁雜和冗餘。

將生命週期的階段與插件目標相互綁定,就可以在特定的階段完成具體的構建任務。例如下面的代碼就是要在 validate 這個階段執行 maven-antrun-plugin 的 run 目標,具體的任務在 元素中定義。

<plugins> 
    <plugin> 
        <groupId>org.apache.maven.plugins</groupId> 
        <artifactId>maven-antrun-plugin</artifactId> 
        <version>1.6</version> 
<executions> 
<execution> 
    <id>version</id> 
   <phase>validate</phase> 
   <configuration> 
<target> 
   具體任務
</target> 
</configuration> 
<goals> 
<goal>  run  </goal> 
    </goals> 
</execution> 
    </executions> 
    </plugin> 
</plugins>

Maven 項目中的插件,依賴和項目構建的輸出都可以由 Maven 的座標進行唯一的區分,基於這種機制,Maven 將所有項目的構件文件放置在一個統一的位置,也就是 Maven 倉庫。所有 Maven 項目可以從同一個 Maven 倉庫中獲取自己所需要的依賴 JAR,這節省了磁盤資源。實際的 Maven 項目中不需要存儲依賴的文件,只需要在 POM 文件中生成依賴關係,在構建的時候 Maven 就會自動去倉庫中下載。

在安裝了 Maven 的機器上,會生成一個 ~.m2\repository 目錄,這個目錄被稱爲本地倉庫,當 Maven 查找需要的依賴時,首先會在本地查找,如果本地倉庫中存在,則直接使用,否則 Maven 回去遠程倉庫查找,查找到後下載到本地進行使用。遠程中央倉庫的地址爲 http://repo1.maven.org/。當然還有一些鏡像倉庫可供使用,有興趣的讀者可以參考 Maven 官方網站的相關介紹。

當個人所在的網絡無法訪問公共的 Maven 倉庫時,可以在 settings.xml 中設置代理服務器。打開 ~.m2\settings.xml,如果沒有則複製 $Maven_HOME/conf/settings.xml 到此路徑下,加入

<proxies> 
  <proxy> 
     <active>true</active> 
     <protocol>http</protocol> 
     <host> 代理地址 </host> 
     <port>8080</port> 
     <username> 用戶名 </username> 
     <password> 密碼 </password> 
   </proxy> 
</proxies>

依賴、聚合和繼承

依賴

我們項目中依賴的 Jar 包可以通過依賴的方式引入,通過在 dependencies 元素下添加 dependency 子元素,可以聲明一個或多個依賴。通過控制依賴的範圍,可以指定該依賴在什麼階段有效。Maven 的幾種依賴範圍:

依賴是具有傳遞性的,例如 Project A 依賴於 Project B,B 依賴於 C,那麼 B 對 C 的依賴關係也會傳遞給 A,如果我們不需要這種傳遞性依賴,也可以用 去除這種依賴的傳遞,如

<dependency> 
<groupId>commons-logging</groupId> 
<artifactId>commons-logging</artifactId> 
<version>1.1.1</version> 
<optional>true<optional> 
</dependency>

假設第三方的 jar 包中沒有使用 來去除某些依賴的傳遞性,那麼可以在當前的 POM 文件中使用 元素聲明排除依賴,exclusions 可以包含一個或者多個 exclusion 子元素,因此可以排除一個或者多個傳遞性依賴。如

<dependency>    
     <groupId>org.springframework</groupId>  
     <artifactId>spring-core</artifactId>  
     <exclusions>  
           <exclusion>      
                <groupId>commons-logging</groupId>          
                <artifactId>commons-logging</artifactId>  
           </exclusion>  
     </exclusions>  
</dependency>

聚合
現實中一個項目往往是由多個 project 構成的,在進行構建時,我們當然不想針對多個 project 分別執行多次構建命令,這樣極容易產生遺漏也會大大降低效率。Maven 的聚合功能可以通過一個父模塊將所有的要構建模塊整合起來,將父模塊的打包類型聲明爲 POM,通過 將各模塊集中到父 POM 中。如清單 7,其中 中間的內容爲子模塊工程名的相對路徑。

清單 7. 聚合
1
2
3
4

…/com.dugeng.project1
…/com.dugeng.project2

父類型的模塊,不需要有源代碼和資源文件,也就是說,沒有 src/main/java 和 src/test/java 目錄。Maven 會首先解析聚合模塊的 POM 文件,分析要構建的模塊,並通過各模塊的依賴關係計算出模塊的執行順序,根據這個潛在的關係依次構建模塊。將各子模塊聚合到父模塊中後,我們就可以對父模塊進行一次構建命令來完成全部模塊的構建。

繼承
在面向對象的編程中我們學會了繼承的概念,繼承是可重用行即消除重複編碼的行爲。Maven 中繼承的用意和麪向對象編程中是一致的。與聚合的實現類似,我們通過構建父模塊將子模塊共用的依賴,插件等進行統一聲明,在聚合和繼承同時使用時,我們可以用同一個父模塊來完成這兩個功能。

例如將 com.dugeng.parent 這個模塊聲明爲 project1 和 project2 的父模塊,那麼我們在 project1 和 2 中用如下代碼聲明父子關係,如

<parent> 
 <groupId>com.dugeng.mavenproject</groupId> 
 <artifactId>com.dugeng.parent</artifactId> 
 <version>0.0.1-SNAPSHOT</version> 
 <relativePath>../com.dugeng.parent/pom.xml</relativePath> 
</parent>

由於父模塊只是用來聲明一些可共用的配置和插件信息,所以它也像聚合模塊一樣只需要包括一個 POM 文件,其它的項目文件如 src/main/java 是不需要的。

聚合和繼承存在一些共性和潛在的聯繫,在實際的應用中,經常將聚合模塊的父模塊和繼承的父模塊定義爲同一個。

並不是所有的 POM 元素都可以被繼承,表 3 是一個可繼承的元素列表。

表 3. 可繼承元素列表
名稱 描述
groupId 項目組 ID
version 項目版本
description 描述信息
organization 組織信息
inceptionYear 創始年份
url 項目的 url 地址
developers 開發者
contributors 貢獻者信息
distributionManagerment 部署信息
issueManagement 缺陷跟蹤系統
ciManagement 持續繼承信息
scm 版本控制信息
mailingList 郵件列表信息
properties 自定義的屬性
dependencies 依賴配置
dependencyManagement 依賴管理配置
repositories 倉庫配置
build 源碼目錄,插件管理等配置
reporting 報告配置
Maven 屬性
在 POM 文件中常常需要引用已定義的屬性以降低代碼的冗餘,提高代碼的可重用性,這樣不僅能降低代碼升級的工作量也能提高代碼的正確率。有些屬性是用戶自定義的,有些屬性是可以直接引用的已定義變量。

Maven 的可用屬性類型可分爲 5 種,它們分別是:

內置屬性。這種屬性跟 Maven Project 自身有關,比如要引入當前 Project 的版本信 息,那麼只需要在使用的位置引用 ${version} 就行了。
Setting 屬性。上文中已經提到 Maven 自身有一個 settings.xml 配置文件,它裏面含有包括倉庫,代理服務器等一些配置信息,利用 ${settings.somename} 就可以得到文件裏相應元素的值。
POM 屬性。這種屬性對應 POM 文件中對應元素的值,例如 project.groupId<groupId></groupId>{project.groupId} 對應了 <groupId></groupId> 中的值,{project.artifactId} 對應了 </ artifactId > 中的值。
系統環境變量。可以使用 env.${name} 來獲得相應 name 對應的環境變量的值,例如 ${env.JAVA_HOME} 得到的就是 JAVA_HOME 的環境變量值。
用戶自定義變量。這種類型的變量是使用最頻繁和廣泛的變量,完全由用戶自己定義。在 POM 文件中加入 元素並將自定義屬性作爲其子元素。格式如

<properties>
  <path>../../sourcecode</path>
</properties>

Maven 3 的新特性

Maven 3 在性能和靈活性方面都比 Maven2 有了很大提升,它的新特性總結起來有以下幾點:

  1. 兼容低版本 Maven,也就是向後兼容,因此用戶可以將 Maven2 的項目移植到 Maven3 上來。

  2. 性能優化。CPU 利用率更高,內存消耗更小,經過優化的 Maven3 比 Maven2 構建速度快出 50% 以上,這對於構建大型項目的開發者來說無疑會節省大量的時間。

  3. 在早先的版本中,開發者必須在子模塊中指定父版本,當進行代碼的遷移或升級時,這會帶來額外的維護工作,Maven3.1 將會消除在子模塊上指定父版本的需要。

4.Maven3 改善了錯誤報告,它會在錯誤報告中提供指向 Maven Wiki 頁面的鏈接,這樣開發者可以方便的查看更全面的錯誤描述和可能的原因。

  1. 增加了 Maven Shell,通常我們可以在系統自帶的 console 裏執行 Maven 命令,但是通過自安裝的 Maven Shell 可以提高生成速度,它是一個是 Maven 的命令行接口工具,可以緩存解析過的 POM,避免了重複調用 Maven 的啓動成本。Maven Shell 不屬於 Maven 發行包的一部分,需要單獨下載。

  2. M2Eclipse 實現了 Maven 和 Eclipse 的集成,與一個使用更廣泛的 IDE 進行集成從而爲開發者帶來的便利是不言而喻的。

結束語
Maven 有着許多實用的特點,它使用了標準的目錄結構和部署。這就使得開發人員能夠適應不同的項目,並且不用學習任何結構方面新的東西,也不用掌握特殊的指令來構建結構。當然,Maven 的使用還不夠普及,相信隨着時間的推移,它的功能會更完善,使用的人羣也會越來越廣泛。

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