背景
本文从实战角度出发,多年踩坑经验总结,能让你快速理解Maven,知其然且知其所以然,全是干货,让我们开始吧。
文章概览
- Maven科普
- Maven插件
- Maven 的 pom.xml 文件
- Maven多子模块项目
- Maven常用命令
- Maven工具执行流程
1. Maven科普
Maven是一个软件项目管理工具,主要用于构建和管理项目,功能比较丰富。在这里笔者着重想告诉你,Maven主要干两件事:
1. Jar包依赖管理
在项目中使用第三方jar是再正常不过的一件事,大家也习以为常。没有maven之前项目使用jar需要我们手动下载,遇到jar依赖问题不得不继续下载直到把所有的jar包下载到项目中,这个过程是痛苦的也浪费程序员宝贵时间。但Jason Van Zyl
这位牛逼的程序员搞定了这件事,他开发的Maven工具可以帮你解决下载jar包,若遇到jar包依赖还能自动下载依赖的jar包,整个过程只需要程序员设定一下配置文件即可完成。
2. 提供标准目录结构
Maven能统一项目目录,这是怎么回事呢?在没有maven工具之前,每个项目的目录结构不同,比如A项目有3个文件夹,B项目有4个文件夹,在小范围内研发没有问题,一旦范围扩大就没有章法显得目录管理混乱。于是Maven就提供统一目录结构,告诉人们只要你用Maven就会是像下面这样结构。
graph TD
subgraph 项目名称
direction TB
A(src)
B(target)
C(pom.xml)
end
subgraph 子目录
direction TB
D[main]
E[test]
F[java]
G[resources]
H[java]
I[resources]
end
A-->D
A-->E
D-->F
D-->G
E-->H
E-->I
3. Maven的配置
配置Maven前默认JDK正确安装,在环境变量中添加M2_HOME=安装路径
,添加path变量%M2_HOME%\bin
,CMD窗口执行mvn -v验证。
4. setting.xml文件
settings.xml 通常有 两个 默认位置,全局配置文件(适用于所有用户)$MAVEN_HOME/conf/settings.xml,用户级配置文件(仅对当前用户生效)C:\Users\你的用户名.m2\settings.xml,这个文件的配置 优先级更高,会覆盖全局 settings.xml。
标签 |
说明 |
<localRepository> |
指定本地 Maven 仓库的路径,默认是 ~/.m2/repository |
<interactiveMode> |
是否允许 Maven 在运行时交互,例如输入密码 (true 允许,false 禁止) |
<usePluginRegistry> |
是否使用 plugin-registry.xml 来管理插件,通常设为 false |
<offline> |
是否开启离线模式 (true 只使用本地缓存,不联网) |
<servers> |
远程仓库的认证信息 (用于私有 Maven 仓库) |
<proxies> |
配置代理服务器,适用于公司网络需要代理访问外网的情况 |
<mirrors> |
Maven 仓库的镜像地址 (常用于加速下载依赖) |
<activeProfiles> |
指定默认激活的配置文件 (profile) |
<profiles> |
定义不同的环境配置,如 development 、production |
<pluginGroups> |
指定插件组,使命令行使用插件时省略 groupId |
<proxies> |
配置 HTTP/HTTPS 代理,适用于公司内网或翻墙 |
文件样例 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- 本地仓库路径 (默认是 ~/.m2/repository) -->
<localRepository>C:\Users\Administrator\.m2\repository</localRepository>
<!-- 交互模式 (true:开启交互,false:关闭交互) -->
<interactiveMode>true</interactiveMode>
<!-- 是否在构建时启用 Maven 插件 (true:启用,false:禁用) -->
<usePluginRegistry>false</usePluginRegistry>
<!-- 是否启用离线模式 (true:只使用本地缓存,false:联网下载依赖) -->
<offline>false</offline>
<!-- 用于指定额外的 Maven 插件组,使得在命令行中使用时不需要指定 groupId -->
<!-- 比如 mvn myplugin:run,如果 myplugin 在 org.codehaus.mojo 组里,就不需要手动写 org.codehaus.mojo:myplugin:run -->
<pluginGroups>
<pluginGroup>org.apache.maven.plugins</pluginGroup>
<pluginGroup>org.codehaus.mojo</pluginGroup>
</pluginGroups>
<!-- 远程仓库认证信息 -->
<servers>
<server>
<id>central</id>
<username>your-username</username>
<password>your-password</password>
</server>
</servers>
<!-- Maven 代理配置 (用于访问外网) -->
<proxies>
<proxy>
<id>my-proxy</id>
<active>false</active> <!-- true 表示启用代理 -->
<protocol>http</protocol>
<host>proxy.example.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>proxypass</password>
<nonProxyHosts>localhost|127.0.0.1</nonProxyHosts>
</proxy>
</proxies>
<!-- 仓库镜像 (加速下载 Maven 依赖) -->
<mirrors>
<!-- 阿里云 Maven 镜像 -->
<mirror>
<id>aliyun-central</id>
<mirrorOf>central</mirrorOf>
<name>Aliyun Maven Repository</name>
<url>https://maven.aliyun.com/repository/central</url>
<layout>default</layout>
</mirror>
<!-- 腾讯云 Maven 镜像 -->
<mirror>
<id>tencent-maven</id>
<mirrorOf>central</mirrorOf>
<name>Tencent Cloud Maven Repository</name>
<url>https://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>
<layout>default</layout>
</mirror>
<!-- 清华大学开源软件镜像站 -->
<mirror>
<id>tsinghua</id>
<mirrorOf>central</mirrorOf>
<name>Tsinghua University Open Source Mirror</name>
<url>https://mirrors.tuna.tsinghua.edu.cn/maven-central/</url>
<layout>default</layout>
</mirror>
</mirrors>
<!-- 配置 Maven 默认的 Active Profile -->
<activeProfiles>
<activeProfile>development</activeProfile>
</activeProfiles>
<!-- 详细的构建配置 -->
<profiles>
<!-- 开发环境配置 -->
<profile>
<id>development</id>
<repositories>
<repository>
<id>aliyun-central</id>
<url>https://maven.aliyun.com/repository/central</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories> <!-- 用于指定 Maven 插件的下载源(类似于 <repositories>,但专门用于插件) -->
<pluginRepository>
<id>aliyun-plugins</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
<!-- 生产环境配置 -->
<profile>
<id>production</id>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</profile>
</profiles>
</settings>
|
2. Maven插件
1. 插件管理
Maven 插件分为 内置插件
和 外部插件
,用于管理整个构建生命周期,比如编译、打包、测试等。
- 使用默认插件,Maven 自带的插件,无需额外安装,可以直接使用。
1
2
3
4
|
mvn clean # 调用 maven-clean-plugin 清理目标目录
mvn compile # 调用 maven-compiler-plugin 编译代码
mvn package # 调用 maven-jar-plugin 打包
mvn install # 调用 maven-install-plugin 安装到本地仓库
|
- 在 pom.xml 中添加插件,如果默认插件不够用,可以在 pom.xml 里 手动添加插件:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
|
2. 运行指定插件
格式:
1
|
mvn <groupId>:<artifactId>:<version>:<goal>
|
使用 mvn 运行插件:
1
2
|
mvn org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile
mvn org.apache.maven.plugins:maven-dependency-plugin:3.2.0:tree
|
3. Maven 的 pom.xml 文件
Maven 的 pom.xml(Project Object Model,项目对象模型)是 Maven 项目的核心配置文件,定义了:
- 项目的基本信息(groupId、artifactId、version)
- 依赖管理(dependencies)
- 构建配置(build)
- 插件管理(plugins)
- 仓库管理(repositories)
- Maven 生命周期配置(profiles、properties 等)
1. 文件的完整标签介绍
基本结构:<project> 根标签,所有 Maven 配置都在这个标签内。
1
2
3
4
5
6
|
<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">
...
</project>
|
基本项目信息:
1
2
3
4
5
|
<modelVersion>4.0.0</modelVersion> <!-- POM 版本 -->
<groupId>com.example</groupId> <!-- 组织 ID,一般是包名 -->
<artifactId>my-app</artifactId> <!-- 项目 ID,生成 JAR/WAR 时的名称 -->
<version>1.0.0</version> <!-- 版本号 -->
<packaging>jar</packaging> <!-- 打包类型 (jar/war/pom) -->
|
依赖管理:
1
2
3
4
5
6
7
8
9
10
11
12
|
<dependencies>
<dependency>
<groupId>junit</groupId> <!-- 依赖的 groupId -->
<artifactId>junit</artifactId> <!-- 依赖的 artifactId -->
<version>4.13.2</version> <!-- 依赖的版本 -->
<!-- compile(默认):编译、运行时都需要
provided:编译时需要,但运行时由容器提供(如 Servlet API)
runtime:运行时需要,但编译时不需要(如数据库驱动)
test:仅测试时使用(如 JUnit)-->
<scope>test</scope> <!-- 作用范围 (compile/test/provided/runtime) -->
</dependency>
</dependencies>
|
插件管理:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<build> <!-- 定义项目的构建过程 -->
<plugins>
<plugin> <!-- Maven 插件,如编译器插件 maven-compiler-plugin -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration> <!-- 插件的配置项,如 Java 版本 -->
<source>17</source> <!-- Java 版本 -->
<target>17</target> <!-- 目标版本 -->
</configuration>
</plugin>
</plugins>
</build>
|
仓库管理:
1
2
3
4
5
6
7
8
|
<repositories> <!-- 指定下载依赖的仓库(默认是 https://repo.maven.apache.org/maven2) -->
<repository>
<id>aliyun-maven</id>
<url>https://maven.aliyun.com/repository/public</url>
<releases><enabled>true</enabled></releases>
<snapshots><enabled>false</enabled></snapshots> <!-- 控制是否允许下载快照版/正式版 -->
</repository>
</repositories>
|
Maven 变量:
1
2
3
4
5
|
<properties> <!-- <properties> 定义变量,避免重复写相同的配置 -->
<maven.compiler.source>17</maven.compiler.source> <!-- 定义 Java 源代码版本 -->
<maven.compiler.target>17</maven.compiler.target> <!-- 定义编译目标版本 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 设定编码 -->
</properties>
|
Maven Profiles(可选):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<profiles>
<profile>
<id>dev</id> <!-- 开发环境 -->
<activation>
<activeByDefault>true</activeByDefault> <!-- 默认启用 -->
</activation>
<properties>
<env>development</env>
</properties>
</profile>
<profile>
<id>prod</id> <!-- 生产环境 -->
<properties>
<env>production</env>
</properties>
</profile>
</profiles>
|
完整的 pom.xml 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
<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.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source> <!-- 使用变量 -->
<target>${maven.compiler.target}</target> <!-- 使用变量 -->
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>aliyun-maven</id>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
</project>
|
2. pom.xml 和 settings.xml 中相同标签的区别
位置 |
标签 |
作用 |
优先级 |
pom.xml |
<repositories> |
项目级别的仓库,仅对当前项目生效 |
低 |
settings.xml |
<repositories> |
全局仓库,适用于所有项目 |
高 |
pom.xml |
<profiles> |
是项目级别的,用于控制当前项目的构建行为 |
低 |
settings.xml |
<profiles> |
是全局级别的,作用于所有 Maven 项目,冲突时,Maven 会优先使用 settings.xml 里的 |
高 |
4. Maven多子模块项目
在 Maven 中,多子模块(Multi-Module)项目的核心是一个父 POM,它管理多个子模块,但自己不包含代码。
1. 创建所有模块
使用 mvn archetype:generate 手动创建会比较麻烦,推荐直接使用以下命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# 创建根目录
进入源码目录
# 创建父项目(不包含代码)
mvn archetype:generate -DgroupId=com.example -DartifactId=my-multi-module-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
rm -rf src # 父项目不需要 src 目录
# 进入父目录
cd my-multi-module-project
# 创建子模块 A(工具模块)
mvn archetype:generate -DgroupId=com.example -DartifactId=module-a -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
# 创建子模块 B(Spring Boot Web 应用)
mvn archetype:generate -DgroupId=com.example -DartifactId=module-b -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
# 创建子模块 C(REST API 服务)
mvn archetype:generate -DgroupId=com.example -DartifactId=module-c -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
|
2. 修改pom.xml文件
父pom
父模块 POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
<?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.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>module-a</module>
<module>module-b</module>
<module>module-c</module>
</modules>
<dependencyManagement> <!-- 统一管理依赖的版本号,但不直接引入依赖,子模块不会自动继承 <dependencyManagement> 中的依赖,必须显式声明 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.4</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
|
子模块 A
子模块 A POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<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>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>module-a</artifactId>
</project>
|
子模块 A 类文件
1
2
3
4
5
6
7
|
package com.example.modulea;
public class Util {
public static String getMessage() {
return "Hello from Module A!";
}
}
|
子模块 B
子模块 B POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<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>
<parent>
<groupId>com.example</groupId>
<artifactId>my-multi-module-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>module-b</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>module-a</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
|
子模块 B 类文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package com.example.moduleb;
import com.example.modulea.Util;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
class HelloController {
@GetMapping("/")
public String hello() {
return Util.getMessage();
}
}
|
子模块 C
子模块 C POM文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<parent> <!-- 子模块会自动继承父 POM 中定义的 dependencies、plugins、properties 等配置。 -->
<groupId>com.example</groupId> <!-- 子模块必须使用父 POM 中定义的 groupId 和 version(除非显式覆盖) -->
<artifactId>my-multi-module-project</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>module-c</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
|
子模块 C 类文件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
package com.example.modulec;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyRestController {
@GetMapping("/api")
public String greet(@RequestParam(value = "name", defaultValue = "World") String name) {
return "Hello, " + name + "!";
}
}
|
3. 构建 & 运行
1
2
3
|
mvn clean install
cd module-b
mvn spring-boot:run
|
访问 http://localhost:8080/,将看到:Hello from Module A!
5. Maven常用命令
- mvn clean:重新构建之前删除target目录及内容,清理旧的编译结果
- mvn compile:将java源码编译成字节码
- mvn test:执行单元测试
- mvn package:打包项目,生成最终文件,如:jar、war
- mvn install:将JAR文件安装到本地Maven仓库(通常位于 ~/.m2/repository 目录下),方便其他项目引用
- mvn deploy:将项目部署到远程仓库,通过pom.xml中的
<distributionManagement>
,找到setting.xml中的<servers>
元素
- mvn clean install:组合命令,先清理项目,然后编译、测试并安装到本地仓库
- mvn clean package:组合命令,先清理项目,然后编译、测试并打包项目
- mvn test - DskipTests:组合命令,跳过测试直接编译打包
- mvn dependency:tree:组合命令,检查项目中使用的依赖关系及其版本
- mvn archetype:generate:组合命令,根据当前项目,生成新的Maven模版,在创建新的项目时候使用自己自定义的模版
6. Maven工具执行流程
graph LR
A(远程仓库)
B(私服)
subgraph Maven
C(setting.xml)
end
subgraph 项目名称
D(pom.xml)
end
E(本机仓库)
A-->B
B-->C
C-->E
E-->D
总结
Maven工具为目前项目构建使用率较高的工具,了解和掌握该工具能大大提高研发效率,请多多实践本文中的相关介绍。