Maven的基礎知識詳細解析

1 簡介

Maven是Apache軟件基金會唯一維護的一款自動化構建工具,專注於服務Java平臺的項目構建依賴管理

Maven是基於項目對象模型(POM),可以通過一小段描述信息來管理項目的構建、報告和文檔的軟件項目管理工具。

在有多個開發團隊環境的情況下,Maven 能夠在很短的時間內使得每項工作都按照標準進行。因爲大部分的工程配置操作都非常簡單並且可複用,在創建報告、檢查、構建和測試自動配置時,Maven 可以讓開發者的工作變得更簡單。

2 完成工作

  • 構建項目(打包,編譯等)
  • 文檔生成
  • 報告
  • 依賴(jar包之間的依賴關係)
  • SCMs
  • 發佈
  • 分發
  • 添加第三方jar包
  • 郵件列表

3 工作原理

4 常用命令

mvn -version/-v —— 顯示版本信息
mvn clean —— 清空生成的文件
mvn compile  ——  編譯
mvn test  ——  編譯並測試
mvn package  ——  生成target目錄,編譯、測試代碼,生成測試報告,生成jar/war文件
mvn site  ——  生成項目相關信息的網站
mvn clean compile  —— 表示先運行清理之後運行編譯,會將代碼編譯到target文件夾中
mvn clean package  —— 運行清理和打包
mvn clean install ——  運行清理和安裝,會將打好的包安裝到本地倉庫中,以便其他的項目可以調用
mvn clean deploy  —— 運行清理和發佈

5 核心概念

概念 說明
LifeCycle 生命週期,maven內置default,sie,clean三個生命週期
Phase 階段,每個生命週期有不同的階段
Plugin 插件,實現實際的構建功能
Goal 一個插件可以實現多個goal,goal具備具體的功能
Execution 通過配置,決定在某個Phase執行哪些Goal
Project maven管理的目標:軟件工程,小的工程可以聚合成大工程
PackageType 爲了便於管理工程,按照構建目標區分成不同的工程類型,如jar,war,ear等
Dependency 依賴,project之間存在依賴關係
DependencyScope maven對依賴定義了不同的作用範圍
Management 可以配置一個工程如何管理依賴關係
Repository 倉庫,存放包,分爲本地庫和遠程庫
Build 構建的動作。使用maven管理工程,主要是指定將project構建到某個phase

6 幾種常見核心概念介紹

6.1 Maven約定的工程目錄

Java開發領域普遍認同的一個觀點:約定>配置>編碼(能用配置解決的問題就不編碼,能基於約定的就不配置)

6.2 POM

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

  • modelVersion:指定當前POM模型的版本,對Maven2和Maven3來說,他只能是4.0.0
  • groupId:項目的所屬公司或組織的域名倒寫
  • artifactId:如果該項目爲一個Maven模塊,則相當於項目名;如果一個項目包含多個子模塊,則它們該模塊的名稱;(一般和項目同名)
  • version:該項目的版本信息
  • name:項目名,作用只是一個更友好的項目名稱,不是必須的。
  • packaging:打包方式,默認爲jar

6.3 依賴管理

Maven 一個核心的特性就是依賴管理。當我們處理多模塊的項目(包含成百上千個模塊或者子項目),模塊間的依賴關係就變得非常複雜,管理也變得很困難。針對此種情形,Maven 提供了一種高度控制的方法。

① 如何引入 jar 包

在代碼開發時,如果需要使用第三方 jar 包提供的類庫,那麼需要在 pom.xml 加入該 jar 包依賴。
例如:使用 zookeeper client

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
  <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.1</version>
  </dependency>
</dependencies>

② Maven 如何解析 jar 包依賴——傳遞依賴

如上所述,在 pom.xml 中引入 zookeeper jar 包依賴,當 Maven 解析該依賴時,需要引入的 jar 包不僅僅只有 zookeeper,還會有 zookeeper 內部依賴的 jar 包,還會有 zookeeper 內部依賴的 jar 包依賴的 jar 包......,依賴關係不斷傳遞,直至沒有依賴。
例如:上述 pom.xml 引入 zookeeper 依賴,實際引入的 jar 包有:

③ 依賴的範圍

有時依賴信息中除了目標 jar 包的座標還有一個 scope 設置,這就是依賴的範圍。依賴的範圍有幾個可選值,常用的有:compile、test、provided 三個,當然還有不常用的 runtime、system..

  • compile默認範圍,編譯測試運行都有效

  • provided:在編譯和測試時有效

  • runtime:在測試和運行時有效

  • test:只在測試時有效

  • system:在編譯和測試時有效,與本機系統關聯,可移植性差

  • 常用依賴範圍有效性總結

④ 包衝突如何產生?

舉個🌰:假設 A->B->C->D1, E->F->D2,D1,D2 分別爲 D 的不同版本。
如果 pom.xml 文件中引入了 A 和 E 之後,按照 Maven 傳遞依賴原則,工程內需要引入的實際 Jar 包將會有:A B C D1 和 E F D2,因此 D1,D2 將會產生包衝突。

⑤ 如何解決包衝突?

Maven 解析 pom.xml 文件時,同一個 jar 包只會保留一個,這樣有效的避免因引入兩個 jar 包導致的工程運行不穩定性。

Maven 默認處理策略

  • 最短路徑優先
    Maven 面對 D1 和 D2 時,會默認選擇最短路徑的那個 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路徑短 1。
  • 最先聲明優先
    如果路徑一樣的話,舉個🌰: A->B->C1, E->F->C2 ,兩個依賴路徑長度都是 2,那麼就選擇最先聲明。

⑥ 移除依賴

如果我們不想通過 A->B->->D1 引入 D1 的話,那麼我們在聲明引入 A 的時候將 D1 排除掉,這樣也避免了包衝突。
舉個🌰:將 zookeeper 的 jline 依賴排除

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
        </exclusion>
    </exclusions>
</dependency>

⑦ 檢測包衝突工具

mvn dependency:help
mvn dependency:analyze
mvn dependency:tree
mvn dependency:tree -Dverbose

6.4 Repository(存儲庫)

Maven Repository/存儲庫,顧名思義是一個存儲JAR文件的倉庫,Maven根據項目中pom.xml文件中提供的jar包依賴信息,從存儲庫中查找並獲取需要的jar包。

① 分類

  • Local Repository – 本地庫:Maven本地存儲庫是本機中的一個目錄。如果目錄不存在,執行maven時就會先創建它。
    默認情況下,maven本地存儲庫是 %USER_HOME%/.m2 目錄,例如:C:\Users\Kevin\.m2
  • Central Repository – 中央庫:Maven中央庫主要放置公共jar包,是由apache maven社區創建的,中央庫的網址是http://repo1.maven.org/maven2,可以通過網址http://search.maven.org/#browse查看有哪些公共jar包。
  • Remote Repository – 遠程庫:Maven遠程庫也是位於網絡上的存儲庫。例如一個公司可能有很多共享的jar包文件,就可以搭建一個公司內部的遠程庫,供衆多開發人員使用;中央庫可以認爲是一個特殊的遠程庫。

Maven搜索依賴項時,會按照:本地庫、中央庫和遠程庫的順序進行。

如果這些庫中沒找到依賴項,Maven將報錯。

6.5 生命週期

Maven有3個內置的構建生命週期:
  • default – 編譯源代碼並處理打包項目相關的所有事情
  • clean – 清理構建輸出,包括生成的編譯類、JAR文件等
  • site – 爲項目生成文檔

 ① Default 生命週期

  • 清理(clean):刪除以前的編譯結果,爲重新編譯做好準備。
  • 驗證(validate):驗證項目是否正確,所有必需的信息是否可用。
  • 編譯(compile):將Java 源程序編譯爲字節碼文件。
  • 測試(test):針對項目中的關鍵點進行測試,確保項目在迭代開發過程中關鍵點的正確性。
  • 打包(package):將一個包含諸多文件的工程封裝爲一個壓縮文件用於安裝或部署。Java 工程對應 jar 包,Web工程對應 war 包。
  • 安裝(install):在 Maven 環境下特指將打包的結果——jar 包或 war 包安裝到本地倉庫中。
  • 報告:在每一次測試後以標準的格式記錄和展示測試結果。
  • 部署(deploy):將打包的結果部署到遠程倉庫或將 war 包部署到服務器上運行。

② Clean 生命週期

Clean 生命週期一共包含了三個階段:

  • pre-clean 執行一些需要在 clean 之前完成的工作
  • clean 移除所有上一次構建生成的文件
  • post-clean 執行一些需要在 clean 之後立刻完成的工作

③ Site 生命週期

  • pre-site 執行一些需要在生成站點文檔之前完成的工作
  • site 生成項目的站點文檔
  • post-site 執行一些需要在生成站點文檔之後完成的工作,並且爲部署做準備
  • site-deploy 將生成的站點文檔部署到特定的服務器上 這裏經常用到的是 site 階段和 site-deploy 階段,用以生成和發佈 Maven 站點,這可是 Maven 相當強大 的功能,Manager 比較喜歡,文檔及統計數據自動生成,很好看。

6.6 插件和目標

 Maven實際上是一個插件執行框架,Maven中的所有任務都是由插件完成的。

Maven插件是構建目標的集合,也稱爲MOJO (Maven Old Java Object)。可以把插件理解爲一個類,而構建目標是類中的方法。構建階段包含一系列的構建目標,可以理解爲按順序調用各個插件中的構建目標(方法),然後一系列的構建階段組成一個構建生命週期。

構建目標可以綁定到多個構建階段,也可以不綁定,就像類的方法可以被調用,也可以不被調用。

<build>
    <plugins>
        <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>${maven.failsafe.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

這是一個故障安全插件的簡單配置,負責運行集成測試。可以看到,插件有兩個主要目標:

  • integration-test: 運行集成測試
  • verify: 驗證所有通過的集成測試

插件類型

Maven提供了2種類型的插件:

  • 構建類插件 – 在構建過程中執行,pom中<build/>元素中配置。
  • 報告類插件 – 在文檔生成過程中執行,pom中<reporting/>元素中配置。

下面是一些maven內置的常用插件:

  • clean
  • compiler
  • surefire
  • jar
  • war
  • javadoc
  • antrun

自定義插件

如果maven內置插件不能滿足項目需求,也可以開發自定義插件。

開發自定義插件可參考官網

6.7 繼承

  • 爲什麼需要繼承機制? 由於非 compile 範圍的依賴信息是不能在“依賴鏈”中傳遞的,所以有需要的工程只能單獨配置
  • 創建父工程 創建父工程和創建一般的 Java 工程操作一致,唯一需要注意的是:打包方式處要設置爲 pom
  • 在子工程中引用父工程 ,從當前目錄到父項目的 pom.xml 文件的相對路徑
 <parent>
 	<groupId>com.starfish.maven</groupId>
	<artifactId>Parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<!-- 以當前文件爲基準的父工程pom.xml文件的相對路徑 -->
	<relativePath>../Parent/pom.xml</relativePath>
</parent>

此時如果子工程的 groupId 和 version 如果和父工程重複則可以刪除。

  • 在父工程中管理依賴 將 Parent 項目中的 dependencies 標籤,用 dependencyManagement 標籤括起來
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement> 
複製代碼

在子項目中重新指定需要的依賴,刪除範圍和版本號

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>

6.8 聚合

  • 爲什麼要使用聚合?

將多個工程拆分爲模塊後,需要手動逐個安裝到倉庫後依賴才能夠生效。修改源碼後也需要逐個手動進 行 clean 操作。而使用了聚合之後就可以批量進行 Maven 工程的安裝、清理工作。

如何配置聚合? 在總的聚合工程中使用 modules/module 標籤組合,指定模塊工程的相對路徑即可

<!-- 配置聚合 -->
<modules>
    <!-- 指定各個子工程的相對路徑 -->
    <module>starfish-learn-grpc</module>
    <module>starfish-learn-kafka</module>
    <module>starfish-web-demo</module>
</modules>

6.9 profile

profile讓你能夠在特定場景下使用與基本配置不同的配置構建項目。你不需要創建多個單獨的POM文件,只需在單個POM文件中包含不同的profile配置,這些profile配置在特定場景下將覆蓋pom中的基本配置。

例如,項目中需要構建開發版本、測試版本以及正式版本,這些版本可以通過在pom文件中添加不同構建profile構建。執行maven時指定不同的構建profile就可以。

<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.qikegu.demo</groupId>
  <artifactId>mybatis-demo</artifactId>
  <version>1.0.0</version>

  <profiles>
      <profile>
          <id>test</id>
          <activation>...</activation>
          <build>...</build>
          <modules>...</modules>
          <repositories>...</repositories>
          <pluginRepositories>...</pluginRepositories>
          <dependencies>...</dependencies>
          <reporting>...</reporting>
          <dependencyManagement>...</dependencyManagement>
          <distributionManagement>...</distributionManagement>
      </profile>
  </profiles>

</project>
  • profile中的元素將覆蓋POM中同名元素的值。
  • <activation>設置觸發profile生效的條件
  • 也可在maven命令行中指定profile:-P profile-name

  

參考

https://www.cnblogs.com/shengs/p/5517220.html

https://juejin.im/post/5e215a9ee51d453c951daa64

https://www.jianshu.com/p/f6ca45865025

https://www.qikegu.com/docs/2471

 

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