一、Maven基礎(chǔ)
1.1 Maven功能
Maven能幫助我們干什么?它主要有兩個功能:
- 依賴管理(jar包管理):在開發(fā)過程中需要大量jar包,我們只需要在Maven的主配置文件中添加相應(yīng)jar包的標識,他就會自動下載相應(yīng)jar包,不用我們自己去到處搜索jar包了
- 構(gòu)建項目:我們可以通過Maven構(gòu)建項目,它定義了一套生命周期,規(guī)范了構(gòu)建流程,可以一鍵構(gòu)建,提高了大型項目的開發(fā)效率

1.2 POM文件
每個maven項目都會有一個pom.xml文件, 在這個文件里面是通過坐標來唯一標識Maven依賴,坐標元素包括groupId、artifactId、version、packaging、classifier(前三個為必選),這些元素的含義:
- groupId:定義當前Maven項目所屬的實際項目
- artifactId:定義實際項目中的一個Maven模塊
- version:定義Maven項目當前所處的版本
- packaging:定義Maven項目打包方式, 通常打包方式與所生成構(gòu)件擴展名對應(yīng),包括:jar(默認)、war、pom、maven-plugin等
- classifier:用來幫助定義構(gòu)建輸出的一些附屬構(gòu)件(如javadoc、sources),不能直接定義項目的classifier,須有插件的幫助
這里提一下version版本的兩種類型:
- SNAPSHOT:泛指以-SNAPSHOT為結(jié)尾的版本號,用于保存開發(fā)過程中的不穩(wěn)定版本號,在mvn deploy時會主動發(fā)布到快照版本號庫中;而使用快照版本號的模塊,在不更改版本號的情況下直接編譯打包時,maven會自己主動從鏡像server上下載最新的快照版本號
- RELEASE:所有非-SNAPSHOT結(jié)尾的版本號則都被認定為RELEASE版本,即正式版,在mvn deploy時會自己主動發(fā)布到正式版本號庫中;而使用正式版本號的模塊在不更改版本號的情況下,編譯打包時假設(shè)本地已經(jīng)存在該版本號的模塊則不會主動去鏡像server下載
1.3 Maven依賴
Maven最著名的就是Maven的依賴管理,它使得我們不必再到開源項目的官網(wǎng)一個個下載開源組件,然后再放入classpath。一個依賴聲明可以包含如下元素:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.7.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
<optional>false</optional>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
依賴范圍Scope
Scope 是用來限制Dependency的作用范圍的, 他會影響maven項目在各個生命周期時導(dǎo)入的package的狀態(tài)。常用scope見下圖:

依賴傳遞性
比如下圖有Maven項目junit,項目commons-logging依賴junit,項目spring-core依賴commons-logging,項目my-app依賴spring-core;那么我們可以說my-app依賴junit;我們執(zhí)行項目my-app時,會自動把spring-core、commons-logging、junit都下載導(dǎo)入到my-app項目的jar包文件夾中,這就是依賴的傳遞性。

假如現(xiàn)在不想執(zhí)行my-app時把junit下載進來,那么我們可以用<exclusions>標簽。
依賴調(diào)節(jié)的原則:
- 如果依賴路徑的長度不同,則短路優(yōu)先
- 依賴路徑長度相同情況下,則先聲明優(yōu)先
依賴分析
mvn dependency:list
查看當前項目的已解析依賴
mvn dependency:tree
查看當前項目的依賴樹
mvn dependency:analyze
自動化分析當前項目的依賴
IDEA可以安裝一個很方便的插件Maven Helper來幫助我們進行依賴管理、排包等操作。
1.4 Maven倉庫
Maven倉庫只有兩大類:
- 本地倉庫:Maven在本地存儲構(gòu)件的地方;
- 遠程倉庫:在遠程倉庫中又分成了2種:
a. 中央倉庫:中央倉庫是默認的遠程倉庫,maven在安裝的時候,自帶的就是中央倉庫的配置;
b. 私服:私服是一種特殊的遠程倉庫,它是架設(shè)在局域網(wǎng)內(nèi)的倉庫服務(wù),私服代理廣域網(wǎng)上的遠程倉庫,供局域網(wǎng)內(nèi)的Maven用戶使用;私服的特性有:
- 節(jié)省外網(wǎng)帶寬
- 加速Maven構(gòu)建
- 部署第三方構(gòu)件
- 提高穩(wěn)定性,增強控制
- 降低中央倉庫負荷
1.5 常用Maven指令
mvn clean compile
清理+編譯
mvn clean test
清理+編譯+執(zhí)行測試
mvn clean package
清理+編譯+打包
mvn clean install
清理+編譯+打包+放置本地倉庫
mvn archetype:generate
創(chuàng)建項目骨架
二、Maven生命周期和插件
Maven生命周期
Maven有三個內(nèi)置的生命周期:default、clean和site。在default的生命周期處理你的項目部署,在clean的生命周期處理項目的清理,在site的生命周期處理你的項目站點文檔的創(chuàng)建。

Maven插件
Maven本身是一個框架,實際的任務(wù)都由插件完成。插件與生命周期階段綁定,用戶通過指定生命周期階段就能夠隱式的通過插件執(zhí)行任務(wù),如:$mvn compiler:compile,冒號前是插件前綴,后面是該插件目標(即: maven-compiler-plugin的compile目標),而該目標綁定了default生命周期的compile階段。
Maven 默認插件目標綁定源碼:
<component>
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
<role-hint>jar</role-hint>
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
<configuration>
<lifecycles>
<lifecycle>
<id>default</id>
<!-- START SNIPPET: jar-lifecycle -->
<phases>
<process-resources>org.apache.maven.plugins:maven-resources-plugin:2.6:resources</process-resources>
<compile>org.apache.maven.plugins:maven-compiler-plugin:3.1:compile</compile>
<process-test-resources>org.apache.maven.plugins:maven-resources-plugin:2.6:testResources</process-test-resources>
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile</test-compile>
<test>org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test</test>
</phases>
<!-- END SNIPPET: jar-lifecycle -->
</lifecycle>
</lifecycles>
</configuration>
</component>
自定義綁定
除了內(nèi)置綁定以外,用戶還能夠自定義將某個插件目標綁定到生命周期的某個階段上。如創(chuàng)建項目的源碼包,maven-source-plugin插件的jar-no-fork目標能夠?qū)㈨椖康闹鞔a打包成jar文件,可以將其綁定到verify階段上:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
其中executions下每個execution子元素可以用來配置執(zhí)行一個任務(wù)。
自定義插件開發(fā)
參考:https://blog.csdn.net/zjf280441589/article/details/53044308/
三、聚合與繼承
Maven的聚合特性(aggregation)能夠使項目的多個模塊聚合在一起構(gòu)建,而繼承特性(inheritance)能夠幫助抽取各模塊相同的依賴、插件等配置,在簡化模塊配置的同時,保持各模塊一致。
例如,父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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.my.app</groupId>
<artifactId>appName</artifactId>
<packaging>pom</packaging>
<version>1.0.0.SNAPSHOT</version>
<modules>
<module>appName-client</module>
<module>appName-core</module>
<module>appName-web</module>
</modules>
<properties>
<finalName>appName</finalName>
<warName>${finalName}.war</warName>
<spring.version>4.0.6.RELEASE</spring.version>
<junit.version>4.12</junit.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<warExplodedDirectory>exploded/${warName}</warExplodedDirectory>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
- packaging: pom,否則無法聚合構(gòu)建
- modules: 實現(xiàn)聚合的核心,module值為被聚合模塊相對于聚合POM的相對路徑,離開聚合POM也能夠獨立構(gòu)建(注: 模塊所處目錄最好與其artifactId一致)
- dependencyManagement: 能讓子POM繼承父POM的配置的同時,又能夠保證子模塊的靈活性:在父POMdependencyManagement元素配置的依賴聲明不會實際引入子模塊中,但能夠約束子模塊dependencies下的依賴的使用(子模塊只需配置groupId與artifactId)
- pluginManagement: 與dependencyManagement類似,配置的插件不會造成實際插件的調(diào)用行為,只有當子POM中配置了相關(guān)plugin元素,才會影響實際的插件行為
子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>
<groupId>com.my.app</groupId>
<artifactId>appName</artifactId>
<version>1.0.0.SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>appName-client</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
可以看到,子POM中并未定義模塊groupId與version,這是因為子POM默認會從父POM繼承了如下元素:
- groupId、version
- dependencies
- developers and contributors
- plugin lists (including reports)
- plugin executions with matching ids
- plugin configuration
- resources
參考:
- 彥薇:Maven原理及使用深度解析
- Maven 核心原理
- maven snapshot快照倉庫和release公布倉庫區(qū)別