
maven package和maven install 有什么區別?
你常用的maven命令有哪些?
<dependencyManagement> 是干什么的?
還有用過其它構建工具嗎? 和maven有啥區別?

這幾個問題都可以脫口而出,你應該是有點 maven 能耐,寫代碼去吧,不用看了
點贊+收藏 就學會系列,文章收錄在 GitHub JavaEgg ,N線互聯網開發必備技能兵器譜
1.Maven是啥:
Maven是Apache軟件基金會唯一維護的一款自動化構建工具,專注于服務Java平臺的項目構建和依賴管理。
Maven是基于項目對象模型(POM),可以通過一小段描述信息來管理項目的構建、報告和文檔的軟件項目管理工具。
2.Maven可以干啥:
- 添加第三方jar包
- jar包之間的依賴關系: Maven 可以替我們自動的將當前 jar 包所依賴的其他所有 jar 包全部導入進來
- 獲取第三方jar包: Maven 提供了一個完全統一規范的 jar 包管理體系,只需要在項目中以坐標的方式依賴一個 jar 包,Maven 就會自動從中央倉庫進行下載到本地倉庫
- 將項目拆分成多個工程模塊
- 構建項目(打包,編譯等)
3.構建項目的幾個主要環節:
- 清理(clean):刪除以前的編譯結果,為重新編譯做好準備
- 編譯(compile):將Java 源程序編譯為字節碼文件
- 測試(test):針對項目中的關鍵點進行測試,確保項目在迭代開發過程中關鍵點的正確性
- 報告:在每一次測試后以標準的格式記錄和展示測試結果
- 打包(package):將一個包含諸多文件的工程封裝為一個壓縮文件用于安裝或部署。Java 工程對應 jar 包,Web工程對應 war 包。
- 安裝(install):在 Maven 環境下特指將打包的結果——jar 包或 war 包安裝到本地倉庫中。
- 部署(deploy):將打包的結果部署到遠程倉庫或將 war 包部署到服務器上運行。
4.Maven常用命令
- 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.Maven核心概念
Maven 能夠實現自動化構建是和它的內部原理分不開的,這里我們從 Maven 的九個核心概念入手, 看看 Maven 是如何實現自動化構建的
- POM
- 約定的目錄結構
- 坐標
- 依賴管理
- 倉庫管理
- 生命周期
- 插件和目標
- 繼承
- 聚合
Maven 的核心程序中僅僅定義了抽象的生命周期,而具體的操作則是由 Maven 的插件來完成的。可是 Maven 的插件并不包含在 Maven 的核心程序中,在首次使用時需要聯網下載。 下載得到的插件會被保存到本地倉庫中。本地倉庫默認的位置是:~.m2\repository。
5.1. Maven約定的工程目錄:

Java開發領域普遍認同的一個觀點:約定>配置>編碼(能用配置解決的問題就不編碼,能基于約定的就不配置)
5.2. POM
Project Object Model:項目對象模型。將 Java 工程的相關信息封裝為對象作為便于操作和管理的模型。
Maven 工程的核心配置。
5.3. 坐標
- Maven 的坐標 使用如下三個向量在 Maven 的倉庫中唯一的確定一個 Maven 工程。
- groupid:公司或組織的域名倒序+當前項目名稱
- artifactId:當前項目的模塊名稱
- version:當前模塊的版本
<groupId>net.lazyegg.maven</groupId>
Hello
<version>0.0.1-SNAPSHOT</version>
復制代碼

-
如何通過坐標到倉庫中查找 jar 包?
- 將 gav 三個向量連起來
```
net.lazyegg.maven+Hello+0.0.1-SNAPSHOT
復制代碼
```

* 以連起來的字符串作為目錄結構到倉庫中查找
net/lazyegg/maven/Hello/0.0.1-SNAPSHOT/Hello-0.0.1-SNAPSHOT.jar
※ 注意:我們自己的 Maven 工程必須執行安裝操作才會進入倉庫。安裝的命令是:mvn install
5.4. 依賴
Maven 中最關鍵的部分,我們使用 Maven 最主要的就是使用它的依賴管理功能。要理解和掌握 Maven 的依賴管理,我們只需要解決以下幾個問題:
① 依賴的目的是什么
當 A jar 包用到了 B jar 包中的某些類時,A 就對 B 產生了依賴,這是概念上的描述。那么如何在項目中以依賴的方式引入一個我們需要的 jar 包呢? 答案非常簡單,就是使用 dependency
標簽指定被依賴 jar 包的坐標就可以了。
<dependency>
<groupId>net.lazyegg.maven</groupId>
Hello
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
復制代碼

② 依賴的范圍
有時依賴信息中除了目標 jar 包的坐標還有一個 scope 設置,這就是依賴的范圍。依賴的范圍有幾個可選值,常用的有:compile、test、provided 三個,當然還有不常用的 runtime、system..
compile:默認范圍,編譯測試運行都有效
provided:在編譯和測試時有效
runtime:在測試和運行時有效
test:只在測試時有效
system:在編譯和測試時有效,與本機系統關聯,可移植性差
常用依賴范圍有效性總結
compile | test | provided | |
---|---|---|---|
主程序 | √ | × | √ |
測試程序 | √ | √ | √ |
參與部署 | √ | × | × |
③ 依賴的傳遞性
A 依賴 B,B 依賴 C,A 能否使用 C 呢?那要看 B 依賴 C 的范圍是不是 compile,如果是則可用,否則不可用。
④ 依賴的排除
如果我們在當前工程中引入了一個依賴是 A,而 A 又依賴了 B,那么 Maven 會自動將 A 依賴的 B 引入當 前工程,但是個別情況下 B 有可能是一個不穩定版,或對當前工程有不良影響。這時我們可以在引入 A 的時候將 B 排除。
<dependency>
<groupId>net.lazyegg.maven</groupId>
Hello
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
commons-logging
</exclusion>
</exclusions>
</dependency>
復制代碼

⑤ 統一管理所依賴 jar 包的版本,對同一個框架的一組 jar 包最好使用相同的版本。為了方便升級框架,可以將 jar 包的版本信息統一提取出來
- 統一聲明版本號
<properties>
<starfish.spring.version>4.1.1.RELEASE</starfish.spring.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
復制代碼

- 引用前面聲明的版本號
<dependency>
<groupId>org.springframework</groupId>
spring-core
<version>${starfish.spring.version}</version>
<scope>compile</scope>
</dependency>
復制代碼

⑥ 依賴的原則:解決 jar 包沖突
- 路徑最短者優先
- 路徑相同時先聲明者優先
項目版本沖突時候的那種蛋疼的感覺,只有疼過的才知道,所以,我們來看看疼過的人是怎么解決的,推薦一個IDEA插件,Maven Helper,比自帶的好用,一目了然

5.5. 倉庫
- 分類
- 本地倉庫:為當前本機電腦上的所有 Maven 工程服務
- 遠程倉庫
- 私服:架設在當前局域網環境下,為當前局域網范圍內的所有 Maven 工程服務
- 中央倉庫:架設在 Internet 上,為全世界所有 Maven 工程服務
- 中央倉庫的鏡像:架設在各個大洲,為中央倉庫分擔流量。減輕中央倉庫的壓力,同時更快的響應用戶請求,比如阿里的鏡像
- 倉庫中的文件
- Maven 的插件
- 我們自己開發的項目的模塊
- 第三方框架或工具的 jar 包 ※ 不管是什么樣的 jar 包,在倉庫中都是按照坐標生成目錄結構,所以可以通過統一的方式查詢或依賴,查詢地址:mvnrepository.com/
5.6. 生命周期
5.6.1. 什么是 Maven 的生命周期?
Maven 生命周期定義了各個構建環節的執行順序,有了這個清單,Maven 就可以自動化的執行構建命令了。
Maven 有三套相互獨立的生命周期,分別是:
- Clean Lifecycle 在進行真正的構建之前進行一些清理工作
- Default Lifecycle 構建的核心部分,編譯,測試,打包,安裝,部署等等
- Site Lifecycle 生成項目報告,站點,發布站點
它們是相互獨立的,你可以僅僅調用 clean 來清理工作目錄,僅僅調用 site 來生成站點。當然你也可以直接運行 mvn clean install site 運行所有這三套生命周期。 每套生命周期都由一組階段(Phase)組成,我們平時在命令行輸入的命令總會對應于一個特定的階段。比 如,運行 mvn clean,這個 clean 是 Clean 生命周期的一個階段。有 Clean 生命周期,也有 clean 階段。
5.6.2. Clean 生命周期
Clean 生命周期一共包含了三個階段:
- pre-clean 執行一些需要在 clean 之前完成的工作
- clean 移除所有上一次構建生成的文件
- post-clean 執行一些需要在 clean 之后立刻完成的工作
5.6.3. Site 生命周期
- pre-site 執行一些需要在生成站點文檔之前完成的工作
- site 生成項目的站點文檔
- post-site 執行一些需要在生成站點文檔之后完成的工作,并且為部署做準備
- site-deploy 將生成的站點文檔部署到特定的服務器上 這里經常用到的是 site 階段和 site-deploy 階段,用以生成和發布 Maven 站點,這可是 Maven 相當強大 的功能,Manager 比較喜歡,文檔及統計數據自動生成,很好看。
5.6.4. Default 生命周期
Default 生命周期是 Maven 生命周期中最重要的一個,絕大部分工作都發生在這個生命周期中(列出一些重要階段)
- validate:驗證工程是否正確,所有需要的資源是否可用。
- compile:編譯項目的源代碼。
- test:使用合適的單元測試框架來測試已編譯的源代碼。這些測試不需要已打包和布署。
- package:把已編譯的代碼打包成可發布的格式,比如 jar、war 等。
- integration-test:如有需要,將包處理和發布到一個能夠進行集成測試的環境。
- verify:運行所有檢查,驗證包是否有效且達到質量標準。
- install:把包安裝到maven本地倉庫,可以被其他工程作為依賴來使用。
- deploy:在集成或者發布環境下執行,將最終版本的包拷貝到遠程的repository,使得其他的開發者或者工程可以共享
5.6.5. 生命周期與自動化構建
運行任何一個階段的時候,它前面的所有階段都會被運行,例如我們運行 mvn install 的時候,代碼會被編譯,測試,打包。這就是 Maven 為什么能夠自動執行構建過程的各個環節的原因。此外,Maven 的插件機制是完全依賴 Maven 的生命周期的,因此理解生命周期至關重要。
5.7. 插件和目標
- Maven 的核心僅僅定義了抽象的生命周期,具體的任務都是交由插件完成的
- 每個插件都能實現多個功能,每個功能就是一個插件目標
- Maven 的生命周期與插件目標相互綁定,以完成某個具體的構建任務 例如:compile 就是插件 maven-compiler-plugin 的一個目標;pre-clean 是插件 maven-clean-plugin 的一個目標
5.8. 繼承
- 為什么需要繼承機制? 由于非 compile 范圍的依賴信息是不能在“依賴鏈”中傳遞的,所以有需要的工程只能單獨配置
- 創建父工程 創建父工程和創建一般的 Java 工程操作一致,唯一需要注意的是:打包方式處要設置為 pom
- 在子工程中引用父工程 ,從當前目錄到父項目的 pom.xml 文件的相對路徑
<parent>
<groupId>com.starfish.maven</groupId>
Parent
<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>
junit
<version>4.9</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
復制代碼

在子項目中重新指定需要的依賴,刪除范圍和版本號
<dependency>
<groupId>junit</groupId>
junit
</dependency>
復制代碼

5.9. 聚合
- 為什么要使用聚合?
將多個工程拆分為模塊后,需要手動逐個安裝到倉庫后依賴才能夠生效。修改源碼后也需要逐個手動進 行 clean 操作。而使用了聚合之后就可以批量進行 Maven 工程的安裝、清理工作。
如何配置聚合? 在總的聚合工程中使用 modules/module 標簽組合,指定模塊工程的相對路徑即可
原本地址:Maven入門,讀完這篇就夠了
博客地址:tengj.top/
前言
夜空中最亮的星,2018請照亮我前行~ Maven是我們日常開發都會用到的,新年第一天,把看過的Maven基礎概念做了整理,作為入門和查閱使用。
正文
Maven概念
Maven作為一個構建工具,不僅能幫我們自動化構建,還能夠抽象構建過程,提供構建任務實現;它跨平臺,對外提供了一致的操作接口,這一切足以使它成為優秀的、流行的構建工具。
Maven不僅是構建工具,還是一個依賴管理工具和項目管理工具,它提供了中央倉庫,能幫我自動下載構件。
maven的安裝
一:因為本人是window系統,所以這里只介紹window下如何安裝,在安裝Maven之前,先確認已經安裝了JDK.

二:接著去Maven官網下載界面下載想要的版本解壓到你想要的目錄就行


三:最后設置一下環境變量,將Maven安裝配置到操作系統環境中,主要就是配置M2_HOME 和PATH兩項,如圖

都搞定后,驗證一下,打開doc輸入 mvn -v如何得到下面信息就說明配置成功了

maven目錄

- bin目錄:
該目錄包含了mvn運行的腳本,這些腳本用來配置java命令,準備好classpath和相關的Java系統屬性,然后執行Java命令。
- boot目錄:
該目錄只包含一個文件,該文件為plexus-classworlds-2.5.2.jar。plexus-classworlds是一個類加載器框架,相對于默認的java類加載器,它提供了更加豐富的語法以方便配置,Maven使用該框架加載自己的類庫。
- conf目錄:
該目錄包含了一個非常重要的文件settings.xml。直接修改該文件,就能在機器上全局地定制Maven的行為,一般情況下,我們更偏向于復制該文件至/.m2/目錄下(表示用戶目錄),然后修改該文件,在用戶范圍定制Maven的行為。
- lib目錄:
該目錄包含了所有Maven運行時需要的Java類庫,Maven本身是分模塊開發的,因此用戶能看到諸如maven-core-3.0.jar、maven-model-3.0.jar之類的文件,此外這里還包含一些Maven用到的第三方依賴如commons-cli-1.2.jar、commons-lang-2.6.jar等等。
Maven常用命令說明
- mvn clean:表示運行清理操作(會默認把target文件夾中的數據清理)。
- mvn clean compile:表示先運行清理之后運行編譯,會將代碼編譯到target文件夾中。
- mvn clean test:運行清理和測試。
- mvn clean package:運行清理和打包。
- mvn clean install:運行清理和安裝,會將打好的包安裝到本地倉庫中,以便其他的項目可以調用。
- mvn clean deploy:運行清理和發布(發布到私服上面)。
上面的命令大部分都是連寫的,大家也可以拆分分別執行,這是活的,看個人喜好以及使用需求,Eclipse Run as對maven項目會提供常用的命令。
設置http代理
編輯seeting.xml文件 有時候你所在的公司基于安全因素考慮,要求你使用通過安全認證的代理訪問因特網。這種情況下,就需要為Maven配置HTTP代理,才能讓它正常訪問外部倉庫,以下載所需要的資源。首先確認自己無法直接訪問公共的maven中央倉庫,直接運行命令ping repo1.maven.org可以檢查網絡。如果真的需要代理,先檢查一下代理服務器是否暢通。比如現在有一個IP地址為218.14.227.197,端口為3128的代理服務,我們可以運行telnet 218.14.227.197 3128來檢測該地址的該端口是否暢通。如果得到出錯信息,需要先獲取正確的代理服務信息,如果telnet連接正確,則輸入ctrl+],然后q,回車,退出即可。
檢查完畢之后,編輯~/.m2/settings.xml文件(如果沒有該文件,則復制$M2_HOME/conf/settings.xml)。添加代理配置如下:
<settings>
...
<proxies>
<proxy>
<id>my-proxy</id>
true
<protocol>http</protocol>
<host>218.14.227.197</host>
<port>3128</port>
<!--
<username>***</username>
<password>***</password>
<nonProxyHosts>
repository.mycom.com|*.google.com
</nonProxyHosts>
-->
</proxy>
</proxies>
...
</settings>
復制代碼

這段配置十分簡單,proxies下可以有多個proxy元素,如果聲明了多個proxy元素,則默認情況下第一個被激活的proxy會生效。這里聲明了一個id為my-proxy的代理,active的值為true表示激活該代理,protocol表示使用的代理協議,這里是http。當然,最重要的是指定正確的主機名(host元素)和端口(port元素)。上述xml配置中注釋掉了username,password,nonProxyHosts幾個元素。當代理服務需要認證時,就需要配置username和password。nonProxyHost元素用來指定哪些主機不需要代理,可以使用"|"符號來分隔多個主機名。此外,該配置也支持通配符,如:*.google.com表示所有以google.com結尾的域名訪問都不要通過代理。
Maven插件安裝,基于IDEA
博主現在使用IDEA來開發的,所以這里介紹一下IDEA中如何配置引入我們上面下載好的Maven

Maven使用
<?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.tengj</groupId>
springBootDemo1
<version>0.0.1-SNAPSHOT</version>
<name>springBootDemo1</name>
</project>
復制代碼

代碼的第一行是XML頭,指定了該xml文檔的版本和編碼方式。 project是所有pom.xml的根元素,它還聲明了一些POM相關的命名空間及xsd元素。 根元素下的第一個子元素modelVersion指定了當前的POM模型的版本,對于Maven3來說,它只能是4.0.0 代碼中最重要是包含了groupId,artifactId和version了。這三個元素定義了一個項目基本的坐標,在Maven的世界,任何的jar、pom或者jar都是以基于這些基本的坐標進行區分的。
groupId定義了項目屬于哪個組,隨意命名,比如谷歌公司的myapp項目,就取名為 com.google.myapp
artifactId定義了當前Maven項目在組中唯一的ID,比如定義hello-world。
version指定了項目當前的版本0.0.1-SNAPSHOT,SNAPSHOT意為快照,說明該項目還處于開發中,是不穩定的。
name元素生命了一個對于用戶更為友好的項目名稱,雖然這不是必須的,但還是推薦為每個POM聲明name,以方便信息交流
依賴的配置
<project>
...
<dependencies>
<dependency>
<groupId>實際項目</groupId>
模塊
<version>版本</version>
<type>依賴類型</type>
<scope>依賴范圍</scope>
<optional>依賴是否可選</optional>
<!—主要用于排除傳遞性依賴-->
<exclusions>
<exclusion>
<groupId>…</groupId>
…
</exclusion>
</exclusions>
</dependency>
<dependencies>
...
</project>
復制代碼

根元素project下的dependencies可以包含一個或者多個dependency元素,以聲明一個或者多個項目依賴。每個依賴可以包含的元素有:
- grounpId、artifactId和version:以來的基本坐標,對于任何一個依賴來說,基本坐標是最重要的,Maven根據坐標才能找到需要的依賴。
- type:依賴的類型,對于項目坐標定義的packaging。大部分情況下,該元素不必聲明,其默認值為jar
- scope:依賴的范圍
- optional:標記依賴是否可選
- exclusions:用來排除傳遞性依賴
依賴范圍
依賴范圍就是用來控制依賴和三種classpath(編譯classpath,測試classpath、運行classpath)的關系,Maven有如下幾種依賴范圍:
- compile:編譯依賴范圍。如果沒有指定,就會默認使用該依賴范圍。使用此依賴范圍的Maven依賴,對于編譯、測試、運行三種classpath都有效。典型的例子是spring-code,在編譯、測試和運行的時候都需要使用該依賴。
- test: 測試依賴范圍。使用次依賴范圍的Maven依賴,只對于測試classpath有效,在編譯主代碼或者運行項目的使用時將無法使用此依賴。典型的例子是Jnuit,它只有在編譯測試代碼及運行測試的時候才需要。
- provided:已提供依賴范圍。使用此依賴范圍的Maven依賴,對于編譯和測試classpath有效,但在運行時候無效。典型的例子是servlet-api,編譯和測試項目的時候需要該依賴,但在運行項目的時候,由于容器以及提供,就不需要Maven重復地引入一遍。
- runtime:運行時依賴范圍。使用此依賴范圍的Maven依賴,對于測試和運行classpath有效,但在編譯主代碼時無效。典型的例子是JDBC驅動實現,項目主代碼的編譯只需要JDK提供的JDBC接口,只有在執行測試或者運行項目的時候才需要實現上述接口的具體JDBC驅動。
- system:系統依賴范圍。該依賴與三種classpath的關系,和provided依賴范圍完全一致,但是,使用system范圍的依賴時必須通過systemPath元素顯示地指定依賴文件的路徑。由于此類依賴不是通過Maven倉庫解析的,而且往往與本機系統綁定,可能構成構建的不可移植,因此應該謹慎使用。systemPath元素可以引用環境變量,如:
<dependency>
<groupId>javax.sql</groupId>
jdbc-stdext
<Version>2.0</Version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
復制代碼

- import:導入依賴范圍。該依賴范圍不會對三種classpath產生實際的影響。
上述除import以外的各種依賴范圍與三種classpath的關系如下:

傳遞性依賴
比如一個account-email項目為例,account-email有一個compile范圍的spring-code依賴,spring-code有一個compile范圍的commons-logging依賴,那么commons-logging就會成為account-email的compile的范圍依賴,commons-logging是account-email的一個傳遞性依賴

有了傳遞性依賴機制,在使用Spring Framework的時候就不用去考慮它依賴了什么,也不用擔心引入多余的依賴。Maven會解析各個直接依賴的POM,將那些必要的間接依賴,以傳遞性依賴的形式引入到當前的項目中。
依賴范圍
假設A依賴于B,B依賴于C,我們說A對于B是第一直接依賴,B對于C是第二直接依賴,A對于C是傳遞性依賴。第一直接依賴和第二直接依賴的范圍決定了傳遞性依賴的范圍,如下圖所示,最左邊一行表示第一直接依賴范圍,最上面一行表示第二直接依賴范圍,中間的交叉單元格則表示傳遞依賴范圍。

從上圖中,我們可以發現這樣的規律:
- 當第二直接依賴的范圍是compile的時候,傳遞性依賴的范圍與第一直接依賴的范圍一致;
- 當第二直接依賴的范圍是test的時候,依賴不會得以傳遞;
- 當第二直接依賴的范圍是provided的時候,只傳遞第一直接依賴范圍也為provided的依賴,切傳遞依賴的范圍同樣為provided;
- 當第二直接依賴的范圍是runtime的時候,傳遞性依賴的范圍與第一直接依賴的范圍一致,但compile列外,此時傳遞性依賴范圍為runtime.
依賴調解 有時候,當傳遞性依賴造成為題的時候,就需要清楚地知道該傳遞性依賴是從哪條依賴路徑引入的。這就是依賴調解的作用,依賴調解有兩大原則: 1. 路徑最近者優先 比如項目有A有這樣的依賴關系:A->B->C->X(1.0)、A->D->X(2.0),X是A的傳遞性依賴,但是兩條依賴路徑上有兩個版本的X,所以根據第一原則,A->D->X(2.0)路徑短,所以X(2.0)會被解析使用 2. 第一聲明者優先 如果路徑都一樣長的話,第一原則就不行了,比如 A->B->Y(1.0)、A->C->Y(2.0),Y(1.0)和Y(2.0)的路徑一樣,所以這時候根據第二原則,先聲明的被解析。
可選依賴

如圖,項目中A依賴B,B依賴于X和Y,如果所有這三個的范圍都是compile的話,那么X和Y就是A的compile范圍的傳遞性依賴,但是如果我想X,Y不作為A的傳遞性依賴,不給他用的話。就需要下面提到的配置可選依賴。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juvenxu.mvnbook</groupId>
project-b
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
mysql-connector-java
<version>5.1.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>postgresql</groupId>
postgresql</groupId>
<version>8.4-701.jdbc3</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>
復制代碼

配置也簡單,在依賴里面添加
<optional>true</optional>
復制代碼

就表示可選依賴了,這樣A如果想用X,Y就要直接顯示的添加依賴了。
排除依賴
有時候你引入的依賴中包含你不想要的依賴包,你想引入自己想要的,這時候就要用到排除依賴了,比如下圖中spring-boot-starter-web自帶了logback這個日志包,我想引入log4j2的,所以我先排除掉logback的依賴包,再引入想要的包就行了

排除依賴代碼結構:
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-logging
</exclusion>
</exclusions>
復制代碼

這里注意:聲明exclustion的時候只需要groupId和artifactId,而不需要version元素,這是因為只需要groupId和artifactId就能唯一定位依賴圖中的某個依賴。
歸類依賴
有時候我們引入的很多依賴包,他們都來自同一個項目的不同模塊,所以他們的版本號都一樣,這時候我們可以用屬性來統一管理版本號
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.juven.mvnbook.account</groupId>
accout-email
<version>1.0.0-SNAPSHOT</version>
<properties>
<springframework.version>1.5.6</springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
spring-core
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
spring-beans
<version>${springframework.version}</version>
</dependency>
</dependencies>
</project>
復制代碼

如圖所示,先通過
</properties>
這里定義你先要的版本
</properties>
復制代碼

來定義,然后在下面依賴使用${}來引入你的屬性。
倉庫
這節將介紹倉庫的由來、布局、分類、配置、內部工作機制、鏡像等概念
倉庫的由來
在Maven世界中,任何一個依賴、插件或者項目構建的輸出,都可以稱為構件。得益于坐標機制,任何Maven項目使用任何一個構件的方式都是完全相同的。在此基礎上,Maven可以在某個位置統一存儲所有Maven項目共享的構件,這個統一的位置就是倉庫。
實際的Maven項目將不再各自存儲其依賴文件,它們只需要聲明這些依賴的坐標,在需要的時候(例如,編譯項目的時候需要將依賴加入到classpath中),Maven會自動根據坐標找到倉庫中的構件,并使用它們。
為了實現重用,項目構建完畢后可生成的構件也可以安裝或者部署到倉庫中,供其他項目使用。
倉庫的布局
任何一個構件都有其唯一的坐標,根據這個坐標可以定義其在倉庫中的唯一存儲路徑,這便是Maven的倉庫布局方式。 該路經與坐標對應關系為groupId/artifactId/version/artifactId-version.packaging。 舉個例子,比如下面這個分頁插件依賴如下:
<dependency>
<groupId>com.github.pagehelper</groupId>
pagehelper-spring-boot-starter
<version>1.1.0</version>
</dependency>
復制代碼

那他對應的倉庫的路徑就是這樣:

Maven倉庫是基于簡單文件系統存儲的,我們也理解其存儲方式、因此,當遇到一些與倉庫相關的問題時,可以很方便的查找相關文件,方便定位問題。
倉庫的分類

本地倉庫
一般來說,在Maven項目目錄下,沒有諸如lib/這樣用來存放依賴文件的目錄。當Maven在執行編譯或測試時,如果需要使用依賴文件,它總是基于坐標使用本地倉庫的依賴文件。
默認情況下,不管在Window還是Linux下,每個用戶在自己用戶目錄下都有一個路徑名為.m2/repository/的倉庫目錄。 如果你想自定義本地倉庫目錄地址。你可以編輯文件~/.m2/settings.xml,設置localRepository元素的值為想要的倉庫地址,例如:
<settings>
<localRepository>D:\java\repository\</localRepository>
</settings>
復制代碼

這樣,該用戶的本地倉庫地址就被設置成了 D:\java\repository\。 需要注意的是,默認情況下,~/.m2/settings.xml文件不存在,用戶需要從Maven安裝目錄復制$M2_HOME/conf/settings.xml文件再進行編輯。
遠程倉庫-中央倉庫
由于最原始的本地倉庫是空的,Maven必須知道至少一個可用的遠程倉庫,才能在執行Maven命令的時候下載到需要的構件。中央倉庫就是這樣一個默認的遠程倉庫,Maven的安裝文件自帶了中央倉庫的配置。
中央倉庫包含了這個世界上絕大多數流行的開源Java構件,以及源碼、作者信息、SCM,信息、許可證信息等,每個月這里都會接受全世界Java程序員大概1億次的訪問,它對全世界Java開發者的貢獻由此可見一斑。
遠程倉庫-私服
私服是一種特殊的遠程倉庫,它是架設在局域網內的倉庫服務,私服代理廣域網上的遠程倉庫,供局域網內的Maven用戶使用。當Maven需要下載構件的時候,它從私服請求,如果私服上不存在該構件,則從外部的遠程倉庫下載,緩存在私服上之后,再為Maven的下載請求提供服務。因此,一些無法從外部倉庫下載到的構件也能從本地上傳到私服上供大家使用。 私服的好處:
- 節省自己的外網速度
- 加速Maven構建
- 部署第三方構建
- 提高穩定性,增強控制
- 降低中央倉庫的負荷
遠程倉庫的配置
在平時的開發中,我們往往不會使用默認的中央倉庫,默認的中央倉庫訪問的速度比較慢,訪問的人或許很多,有時候也無法滿足我們項目的需求,可能項目需要的某些構件中央倉庫中是沒有的,而在其他遠程倉庫中有,如JBoss Maven倉庫。這時,可以在pom.xml中配置該倉庫,代碼如下:
<!-- 配置遠程倉庫 -->
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
復制代碼

- repository:在repositories元素下,可以使用repository子元素聲明一個或者多個遠程倉庫。
- id:倉庫聲明的唯一id,尤其需要注意的是,Maven自帶的中央倉庫使用的id為central,如果其他倉庫聲明也使用該id,就會覆蓋中央倉庫的配置。
- name:倉庫的名稱,讓我們直觀方便的知道倉庫是哪個,暫時沒發現其他太大的含義。
- url:指向了倉庫的地址,一般來說,該地址都基于http協議,Maven用戶都可以在瀏覽器中打開倉庫地址瀏覽構件。
- releases和snapshots:用來控制Maven對于發布版構件和快照版構件的下載權限。需要注意的是enabled子元素,該例中releases的enabled值為true,表示開啟JBoss倉庫的發布版本下載支持,而snapshots的enabled值為false,表示關閉JBoss倉庫的快照版本的下載支持。根據該配置,Maven只會從JBoss倉庫下載發布版的構件,而不會下載快照版的構件。
- layout:元素值default表示倉庫的布局是Maven2及Maven3的默認布局,而不是Maven1的布局。基本不會用到Maven1的布局。
- 其他:對于releases和snapshots來說,除了enabled,它們還包含另外兩個子元素updatePolicy和checksumPolicy。
1:元素updatePolicy用來配置Maven從遠處倉庫檢查更新的頻率,默認值是daily,表示Maven每天檢查一次。其他可用的值包括:never-從不檢查更新;always-每次構建都檢查更新;interval:X-每隔X分鐘檢查一次更新(X為任意整數)。
2:元素checksumPolicy用來配置Maven檢查校驗和文件的策略。當構建被部署到Maven倉庫中時,會同時部署對應的檢驗和文件。在下載構件的時候,Maven會驗證校驗和文件,如果校驗和驗證失敗,當checksumPolicy的值為默認的warn時,Maven會在執行構建時輸出警告信息,其他可用的值包括:fail-Maven遇到校驗和錯誤就讓構建失敗;ignore-使Maven完全忽略校驗和錯誤。
遠程倉庫的認證
大部分的遠程倉庫不需要認證,但是如果是自己內部使用,為了安全起見,還是要配置認證信息的。 配置認證信息和配置遠程倉庫不同,遠程倉庫可以直接在pom.xml中配置,但是認證信息必須配置在settings.xml文件中。這是因為pom往往是被提交到代碼倉庫中供所有成員訪問的,而settings.xml一般只存在于本機。因此,在settings.xml中配置認證信息更為安全。
<settings>
2 ...
3 <!--配置遠程倉庫認證信息-->
4 <servers>
5 <server>
6 <id>releases</id>
7 <username>admin</username>
8 <password>admin123</password>
9 </server>
10 </servers>
11 ...
12 </settings>
復制代碼

這里除了配置賬號密碼之外,值關鍵的就是id了,這個id要跟你在pom.xml里面配置的遠程倉庫repository的id一致,正是這個id將認證信息與倉庫配置聯系在了一起。
部署構件至遠程倉庫
我們自己搭建遠程倉庫的目的就是為了可以方便部署我們自己項目的構件以及一些無法從外部倉庫直接獲取的構件。這樣才能在開發時,供其他對團隊成員使用。 Maven除了能對項目進行編譯、測試、打包之外,還能將項目生成的構件部署到遠程倉庫中。首先,需要編輯項目的pom.xml文件。配置distributionManagement元素,代碼如下:
<distributionManagement>
<repository>
<id>releases</id>
<name>public</name>
<url>http://59.50.95.66:8081/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Snapshots</name>
<url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
復制代碼

看代碼,從命名上就看的出來區別,repository表示表示發布版本(穩定版本)構件的倉庫,snapshotRepository表示快照版本(開發測試版本)的倉庫。這兩個元素都需要配置id、name和url,id為遠程倉庫的唯一標識,name是為了方便人閱讀,關鍵的url表示該倉庫的地址。
配置好了就運行命令mvn clean deploy,Maven就會將項目構建輸出的構件部署到配置對應的遠程倉庫,如果項目當前的版本是快照版本,則部署到快照版本的倉庫地址,否則就部署到發布版本的倉庫地址。 當前項目是快照還是發布版本是通過 true 這個來區分的。忘記的同學在看看上面的## 遠程倉庫的配置。
鏡像
如果倉庫X可以提供倉庫Y存儲的所有內容,那么就可以認為X是Y的一個鏡像。用過Maven的都知道,國外的中央倉庫用起來太慢了,所以選擇一個國內的鏡像就很有必要,我推薦國內的阿里云鏡像。 阿里云鏡像:配置很簡單,修改conf文件夾下的settings.xml文件,添加如下鏡像配置:
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
復制代碼

上例子中,的值為central,表示該配置為中央庫的鏡像,任何對于中央倉庫的請求都會轉至該鏡像,用戶也可以用同樣的方法配置其他倉庫的鏡像
這里介紹下<mirrorOf>
配置的各種選項
-
<mirrorOf>*<mirrorOf>
:匹配所有遠程倉庫。 -
<mirrorOf>external:*<mirrorOf>
:匹配所有遠程倉庫,使用localhost的除外,使用file://協議的除外。也就是說,匹配所有不在本機上的遠程倉庫。 -
<mirrorOf>repo1,repo2<mirrorOf>
:匹配倉庫repo1h和repo2,使用逗號分隔多個遠程倉庫。 -
<mirrorOf>*,!repo1<mirrorOf>
:匹配所有遠程倉庫,repo1除外,使用感嘆號將倉庫從匹配中排除。
需要注意的是,由于鏡像倉庫完全屏蔽了被鏡像倉庫,當鏡像倉庫不穩定或者停止服務的時候,Maven仍將無法訪問被鏡像倉庫,因而將無法下載構件。
倉庫服務搜索
這里介紹2個提供倉庫服務搜索的地址:
- Sonatype Nexus:repository.sonatype.org/
- MVNrepository:mvnrepository.com/
總結
暫時先這樣,后面繼續補充更新本篇,關于私服搭建的會另外開一片介紹。 本篇基于《Maven實戰》整理提煉。需要電子書小伙伴可關注博主微信公眾號:嘟爺java超神學堂(java2Learn)回復關鍵字 maven
獲取電子書。
作者:嘟嘟MD
鏈接:https://juejin.cn/post/6844903543711907848
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
<!-- 配置聚合 -->
<modules>
<!-- 指定各個子工程的相對路徑 -->
<module>starfish-learn-grpc</module>
<module>starfish-learn-kafka</module>
<module>starfish-web-demo</module>
</modules>

微信公眾號【程序員黃小斜】作者是前螞蟻金服Java工程師,專注分享Java技術干貨和求職成長心得,不限于BAT面試,算法、計算機基礎、數據庫、分布式、spring全家桶、微服務、高并發、JVM、Docker容器,ELK、大數據等。關注后回復【book】領取精選20本Java面試必備精品電子書。