Maven配置文件详解
# Maven 配置文件详解
Maven 有两个核心配置文件:settings.xml 和 pom.xml。
settings.xml是 Maven 的全局/用户级配置文件,pom.xml是项目级配置文件。
本文将系统讲解这两个配置文件的结构和常用配置项。
# 一、settings.xml
# 文件位置
settings.xml 存在两个位置,加载优先级从高到低:
| 位置 | 作用范围 | 说明 |
|---|---|---|
~/.m2/settings.xml | 用户级 | 当前用户的 Maven 配置(推荐修改此文件) |
${MAVEN_HOME}/conf/settings.xml | 全局级 | Maven 安装目录下的全局配置 |
如果两个文件都存在,用户级配置会与全局级配置合并,用户级配置优先。
# 完整配置结构
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0
https://maven.apache.org/xsd/settings-1.2.0.xsd">
<!-- 本地仓库路径 -->
<localRepository>/path/to/local/repo</localRepository>
<!-- 交互模式 -->
<interactiveMode>true</interactiveMode>
<!-- 离线模式 -->
<offline>false</offline>
<!-- 插件组 -->
<pluginGroups>
<pluginGroup>org.apache.maven.plugins</pluginGroup>
</pluginGroups>
<!-- 代理配置 -->
<proxies>
<proxy>
<id>optional</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.host.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>proxypass</password>
<nonProxyHosts>local.net|some.host.com</nonProxyHosts>
</proxy>
</proxies>
<!-- 服务器认证配置 -->
<servers>
<server>
<id>server-id</id>
<username>username</username>
<password>password</password>
</server>
</servers>
<!-- 镜像配置 -->
<mirrors>
<mirror>
<id>mirror-id</id>
<mirrorOf>central</mirrorOf>
<name>Mirror Name</name>
<url>https://mirror.url.com/repository</url>
</mirror>
</mirrors>
<!-- 环境配置 -->
<profiles>
<profile>
<id>profile-id</id>
<!-- ... -->
</profile>
</profiles>
<!-- 激活的 Profile -->
<activeProfiles>
<activeProfile>profile-id</activeProfile>
</activeProfiles>
</settings>
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
# 核心配置项详解
# 1. localRepository — 本地仓库路径
<localRepository>D:/maven-repository</localRepository>
指定本地仓库的存储路径。默认为 ~/.m2/repository。建议修改到非系统盘,避免占用 C 盘空间。
# 2. interactiveMode — 交互模式
<interactiveMode>true</interactiveMode>
是否使用交互模式。设为 false 时 Maven 不会提示用户输入。默认为 true。
# 3. offline — 离线模式
<offline>false</offline>
是否开启离线模式。设为 true 时 Maven 不会尝试从网络下载依赖。适用于无网络环境。
# 4. pluginGroups — 插件组
<pluginGroups>
<pluginGroup>org.apache.tomcat.maven</pluginGroup>
</pluginGroups>
2
3
配置插件组后,可以在命令行中直接使用插件前缀,而无需指定完整的 groupId。例如配置了 org.apache.tomcat.maven 后,可以直接使用 mvn tomcat:run。
# 5. proxies — 代理配置
<proxies>
<proxy>
<id>my-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>proxy.company.com</host>
<port>8080</port>
<username>proxyuser</username>
<password>proxypass</password>
<nonProxyHosts>localhost|127.0.0.1|*.internal.com</nonProxyHosts>
</proxy>
</proxies>
2
3
4
5
6
7
8
9
10
11
12
| 标签 | 说明 |
|---|---|
id | 代理的唯一标识 |
active | 是否激活该代理 |
protocol | 代理协议(http / https / socks) |
host | 代理服务器地址 |
port | 代理服务器端口 |
username | 代理认证用户名 |
password | 代理认证密码 |
nonProxyHosts | 不走代理的主机列表(用 | 分隔) |
# 6. servers — 服务器认证配置
<servers>
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
</servers>
2
3
4
5
6
7
8
9
10
11
12
| 标签 | 说明 |
|---|---|
id | 服务器唯一标识,需与 pom.xml 中 <repository> 的 <id> 一致 |
username | 认证用户名 |
password | 认证密码 |
还可以配置
<privateKey>和<passphrase>用于 SSH 认证,以及<filePermissions>和<directoryPermissions>用于设置文件权限。
# 7. mirrors — 镜像配置
<mirrors>
<!-- 阿里云公共仓库 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
2
3
4
5
6
7
8
9
| 标签 | 说明 |
|---|---|
id | 镜像的唯一标识 |
mirrorOf | 指定镜像替代的仓库范围 |
name | 镜像名称 |
url | 镜像仓库地址 |
mirrorOf 常用取值:
| 取值 | 说明 |
|---|---|
central | 仅替代中央仓库 |
* | 替代所有仓库 |
external:* | 替代所有外部仓库(不包括 localhost) |
repo1,repo2 | 替代指定 id 的仓库 |
*,!repo1 | 替代除 repo1 外的所有仓库 |
常用国内镜像:
<mirrors>
<!-- 阿里云 -->
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
<!-- 华为云 -->
<mirror>
<id>huaweicloud</id>
<mirrorOf>central</mirrorOf>
<name>华为云公共仓库</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</mirror>
<!-- 腾讯云 -->
<mirror>
<id>tencent</id>
<mirrorOf>central</mirrorOf>
<name>腾讯云公共仓库</name>
<url>https://mirrors.cloud.tencent.com/nexus/repository/maven-public/</url>
</mirror>
</mirrors>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 8. profiles — 环境配置
<profiles>
<profile>
<id>jdk-8</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.8</jdk>
</activation>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
2
3
4
5
6
7
8
9
10
11
12
13
14
Profile 可以包含以下配置:
<repositories>:远程仓库配置<pluginRepositories>:插件仓库配置<properties>:属性定义<activation>:激活条件
activation 激活条件:
<activation>
<!-- 默认激活 -->
<activeByDefault>true</activeByDefault>
<!-- 根据 JDK 版本激活 -->
<jdk>1.8</jdk>
<!-- 根据操作系统激活 -->
<os>
<name>Windows 10</name>
<family>Windows</family>
<arch>x86</arch>
<version>10.0</version>
</os>
<!-- 根据系统属性激活 -->
<property>
<name>mavenVersion</name>
<value>3.0</value>
</property>
<!-- 根据文件存在性激活 -->
<file>
<exists>${basedir}/file2.properties</exists>
<missing>${basedir}/file1.properties</missing>
</file>
</activation>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 9. activeProfiles — 激活的 Profile
<activeProfiles>
<activeProfile>jdk-8</activeProfile>
</activeProfiles>
2
3
显式激活指定的 Profile,无论其 activation 条件是否满足。
# 二、pom.xml
# 文件位置
pom.xml 位于 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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ==================== 项目坐标 ==================== -->
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<!-- ==================== 父项目 ==================== -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<relativePath>../parent-project/pom.xml</relativePath>
</parent>
<!-- ==================== 项目信息 ==================== -->
<name>My Project</name>
<description>项目描述</description>
<url>https://github.com/example/my-project</url>
<inceptionYear>2024</inceptionYear>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<developers>
<developer>
<id>dev1</id>
<name>开发者姓名</name>
<email>dev@example.com</email>
</developer>
</developers>
<scm>
<url>https://github.com/example/my-project</url>
<connection>scm:git:git://github.com/example/my-project.git</connection>
<developerConnection>scm:git:git@github.com:example/my-project.git</developerConnection>
</scm>
<!-- ==================== 属性 ==================== -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.3.29</spring.version>
</properties>
<!-- ==================== 依赖管理 ==================== -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- ==================== 依赖 ==================== -->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>
<!-- ==================== 模块(聚合) ==================== -->
<modules>
<module>module-a</module>
<module>module-b</module>
</modules>
<!-- ==================== 构建 ==================== -->
<build>
<finalName>my-project</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- ==================== 环境配置 ==================== -->
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>dev</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles>
<!-- ==================== 仓库 ==================== -->
<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>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
</pluginRepositories>
<!-- ==================== 发布管理 ==================== -->
<distributionManagement>
<repository>
<id>nexus-releases</id>
<url>http://localhost:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<url>http://localhost:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# 核心配置项详解
# 1. 项目坐标
<groupId>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
2
3
4
| 标签 | 说明 | 是否必填 |
|---|---|---|
groupId | 组织 ID(域名反写) | 是 |
artifactId | 项目 ID(模块名称) | 是 |
version | 版本号 | 是 |
packaging | 打包方式(jar/war/pom/ear) | 否(默认 jar) |
# 2. parent — 父项目
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<relativePath>../parent-project/pom.xml</relativePath>
</parent>
2
3
4
5
6
子项目通过 <parent> 继承父项目的配置。<relativePath> 指定父 POM 的相对路径,默认值为 ../pom.xml。
# 3. properties — 属性定义
<properties>
<!-- 编码配置 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 编译器配置 -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- 自定义版本号 -->
<spring.version>5.3.29</spring.version>
<junit.version>4.13.2</junit.version>
</properties>
2
3
4
5
6
7
8
9
10
11
12
13
定义的属性可以在 POM 文件中通过 ${属性名} 引用,便于统一管理版本号。
# 4. dependencies — 依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.29</version>
<scope>compile</scope>
<optional>false</optional>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
详细的依赖管理说明请参考 Maven依赖管理 (opens new window)。
# 5. dependencyManagement — 依赖管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.29</version>
</dependency>
</dependencies>
</dependencyManagement>
2
3
4
5
6
7
8
9
仅声明依赖版本,不会实际引入依赖。子模块需要显式声明才会引入。
# 6. build — 构建配置
<build>
<!-- 最终构建产物名称 -->
<finalName>my-project</finalName>
<!-- 目录配置 -->
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<!-- 资源文件配置 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<excludes>
<exclude>**/*.bak</exclude>
</excludes>
</resource>
</resources>
<!-- 插件配置 -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!-- 插件管理 -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
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
<resource> 标签说明:
| 标签 | 说明 |
|---|---|
directory | 资源文件目录 |
filtering | 是否开启资源过滤(变量替换) |
includes | 包含的文件模式 |
excludes | 排除的文件模式 |
targetPath | 资源文件的目标路径 |
# 7. repositories — 仓库配置
<repositories>
<repository>
<id>central</id>
<name>Maven Central</name>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| 标签 | 说明 |
|---|---|
id | 仓库唯一标识 |
name | 仓库名称 |
url | 仓库地址 |
releases | 发布版本配置 |
snapshots | 快照版本配置 |
enabled | 是否启用 |
updatePolicy | 更新策略(always/never/daily/interval:X) |
checksumPolicy | 校验策略(fail/warn/ignore) |
# 8. distributionManagement — 发布管理
<distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Releases Repository</name>
<url>http://localhost:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>Snapshots Repository</name>
<url>http://localhost:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
2
3
4
5
6
7
8
9
10
11
12
| 标签 | 说明 |
|---|---|
repository | 发布版本仓库配置 |
snapshotRepository | 快照版本仓库配置 |
mvn deploy命令会将构建产物发布到此处配置的仓库。<id>需与settings.xml中<server>的<id>对应。
# 9. profiles — 环境配置
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>dev</env>
<db.url>jdbc:mysql://localhost:3306/dev_db</db.url>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
<db.url>jdbc:mysql://prod-server:3306/prod_db</db.url>
</properties>
</profile>
</profiles>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Profile 中可以覆盖 dependencies、dependencyManagement、build、repositories 等配置,实现不同环境下的差异化构建。
# 三、Super POM(超级 POM)
所有 Maven 项目的 POM 都隐式继承自 Super POM。Super POM 定义了 Maven 的默认配置,包括:
- 默认的目录结构(
src/main/java、src/test/java等) - 默认的中央仓库地址
- 默认的插件绑定
可以通过以下命令查看当前项目的有效 POM(包含继承的所有配置):
mvn help:effective-pom
# 四、配置优先级
Maven 配置的优先级从高到低为:
命令行参数 > 用户级 settings.xml > 全局级 settings.xml > 项目 pom.xml > Super POM
# 五、Maven 依赖解析顺序
理解 Maven 的依赖解析顺序,对于排查"依赖找不到"或"依赖版本不对"等问题至关重要。
# 依赖解析的完整流程
当 Maven 需要获取一个依赖时,会按以下顺序依次查找:
1. 本地仓库
↓(未找到)
2. 镜像仓库(如果配置了 <mirror> 且匹配)
↓(未找到 / 无匹配镜像)
3. 远程仓库(<repositories> 中配置的仓库,按声明顺序逐个尝试)
↓(全部未找到)
4. 中央仓库(Maven Central)
↓(未找到)
5. 构建失败,抛出异常
2
3
4
5
6
7
8
9
# 详细说明
# 第 1 步:查找本地仓库
Maven 首先在本地仓库(<localRepository> 指定的路径)中查找依赖。
- 如果找到且版本匹配,直接使用,不会访问任何远程仓库。
- 如果是
SNAPSHOT版本,会根据<updatePolicy>决定是否检查远程仓库是否有更新。
# 第 2 步:镜像拦截(<mirror> 的作用)
如果本地仓库没有找到,Maven 在访问远程仓库之前,会先检查 settings.xml 中的 <mirrors> 配置。
镜像匹配规则:
Maven 会遍历所有 <mirror> 配置,检查每个镜像的 <mirrorOf> 是否匹配当前要访问的仓库 ID:
<mirrorOf> 值 | 匹配规则 |
|---|---|
central | 仅匹配 ID 为 central 的仓库(即中央仓库) |
* | 匹配所有仓库 |
external:* | 匹配所有非 localhost 的仓库 |
repo1,repo2 | 匹配 ID 为 repo1 或 repo2 的仓库 |
*,!repo1 | 匹配除 repo1 外的所有仓库 |
关键点:
- 第一个匹配的镜像生效:Maven 遍历
<mirrors>列表,使用第一个匹配到的镜像,后续镜像不再检查。 - 镜像会完全替代被镜像的仓库:一旦某个仓库被镜像替代,Maven 只会访问镜像地址,不会访问原始仓库地址。
- 镜像不会替代所有仓库:只有
<mirrorOf>匹配到的仓库才会被替代,未匹配的仓库仍按原地址访问。
# 第 3 步:访问远程仓库(<repositories>)
如果没有匹配的镜像,或者镜像中也没有找到依赖,Maven 会按照 <repositories> 中声明的顺序,逐个访问远程仓库。
远程仓库的来源:
- Super POM 中的中央仓库(ID 为
central) - 父 POM 中的
<repositories>配置 - 当前 POM 中的
<repositories>配置 - settings.xml 中激活的 Profile 里的
<repositories>配置
仓库合并与去重:
- 所有来源的仓库会合并为一个列表。
- 如果多个来源定义了相同 ID 的仓库,子 POM 的配置会覆盖父 POM 的配置。
- 仓库按声明顺序依次尝试,找到即停止。
# 第 4 步:访问中央仓库
如果以上仓库都没有找到依赖,Maven 会访问 Super POM 中定义的中央仓库(https://repo.maven.apache.org/maven2)。
注意:如果配置了
<mirrorOf>central</mirrorOf>的镜像,中央仓库会被镜像替代,Maven 不会直接访问 Maven Central。
# 第 5 步:构建失败
如果所有仓库都找不到依赖,Maven 会抛出类似以下错误:
Could not find artifact com.example:missing-lib:jar:1.0.0 in central (https://repo.maven.apache.org/maven2)
# <mirror> 和 <repositories> 同时配置时的行为
这是最常引起困惑的场景。假设有以下配置:
settings.xml:
<mirrors>
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
2
3
4
5
6
7
pom.xml:
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
<repository>
<id>my-company</id>
<url>http://nexus.company.com/repository/maven-public/</url>
</repository>
</repositories>
2
3
4
5
6
7
8
9
10
解析行为:
| 要查找的依赖 | 解析过程 |
|---|---|
| 公共开源依赖 | 本地仓库 → 阿里云镜像(替代 central)→ my-company 仓库 → 构建失败 |
| 公司内部依赖 | 本地仓库 → 阿里云镜像(找不到)→ my-company 仓库(找到) |
关键理解:
<mirror>不会替代<repositories>中所有仓库,只替代<mirrorOf>匹配到的仓库。central仓库被阿里云镜像替代后,Maven 访问的是阿里云地址,而非 Maven Central 原始地址。my-company仓库没有被任何镜像匹配,仍然按原始地址访问。- Maven 会依次尝试所有可用仓库,直到找到依赖为止。
# 六、.lastUpdated 文件与依赖下载失败问题
在开发过程中,经常会遇到 IDEA 中依赖爆红、提示 Could not find artifact ... 的问题,这通常与 .lastUpdated 文件有关。
# 什么是 .lastUpdated 文件?
当 Maven 从远程仓库下载依赖失败时(网络超时、仓库不可达、404 等),会在本地仓库对应目录下生成一个 .lastUpdated 文件,例如:
~/.m2/repository/com/example/my-lib/1.0.0/
├── my-lib-1.0.0.jar
├── my-lib-1.0.0.jar.lastUpdated ← 下载失败的标记
├── my-lib-1.0.0.pom
└── my-lib-1.0.0.pom.lastUpdated ← 下载失败的标记
2
3
4
5
.lastUpdated 文件记录了上次下载失败的时间和信息,它的作用是:
- Maven 在默认时间窗口内(通常是 24 小时)不会重试下载该依赖,即使你再次执行
mvn命令。 - 这是一种避免频繁重试的缓存机制,防止因网络问题导致每次构建都去尝试下载不存在的依赖。
# 为什么本地有 jar 包但 IDEA 还是爆红?
这是一个非常常见的困惑。Maven 判断本地仓库是否有依赖,不是看 jar 文件存不存在,而是看 jar 和 pom 文件是否都完整。
Maven 解析依赖时需要以下文件同时存在:
| 文件 | 作用 | 缺失后果 |
|---|---|---|
xxx.jar | 依赖的二进制文件 | 编译/运行时找不到类 |
xxx.pom | 依赖的 POM 文件,描述该依赖的传递依赖等信息 | Maven 认为依赖不完整,不认可该依赖 |
常见场景:
- jar 包下载成功,但 POM 下载失败:Maven 生成了
xxx.pom.lastUpdated,虽然 jar 包存在,但 POM 缺失,Maven 认为依赖不完整,于是去远程仓库重新下载,远程仓库也没有,就报错了。 - 手动复制 jar 包到本地仓库:只放了 jar 文件,没有放 POM 文件,Maven 无法识别。
.lastUpdated文件阻止重试:即使远程仓库后来上传了该依赖,由于.lastUpdated文件的存在,Maven 在时间窗口内不会重试下载。
# 解决方法
# 方法一:删除 .lastUpdated 文件后重新刷新
手动删除本地仓库中对应的 .lastUpdated 文件,然后重新 Reload Maven Project:
# 删除指定依赖的 .lastUpdated 文件(Windows)
del D:\maven-repository\com\example\my-lib\1.0.0\*.lastUpdated
# 批量删除本地仓库中所有 .lastUpdated 文件(PowerShell)
Get-ChildItem -Path "D:\maven-repository" -Recurse -Filter "*.lastUpdated" | Remove-Item -Force
2
3
4
5
# 方法二:使用 -U 参数强制更新
mvn clean install -U
-U 参数会强制忽略 .lastUpdated 文件,重新从远程仓库下载 SNAPSHOT 和失败的依赖。
注意:
-U只对 SNAPSHOT 版本强制更新。如果是 RELEASE 版本且下载失败,-U不一定有效,仍需手动删除.lastUpdated文件。
# 方法三:使用 mvn install:install-file 安装本地 jar 包
如果远程仓库没有该依赖(如第三方私有 jar 包),需要手动将 jar 包安装到本地仓库。不要直接复制文件,应使用 Maven 命令安装,这样 Maven 会自动生成 POM 文件:
mvn install:install-file \
-Dfile=/path/to/my-lib-1.0.0.jar \
-DgroupId=com.example \
-DartifactId=my-lib \
-Dversion=1.0.0 \
-Dpackaging=jar
2
3
4
5
6
执行后 Maven 会在本地仓库中自动创建完整的目录结构,包括 jar 和 pom 文件。
如果该依赖有传递依赖,可以通过
-DpomFile参数指定已有的 POM 文件:mvn install:install-file -Dfile=my-lib-1.0.0.jar -DpomFile=my-lib-1.0.0.pom1
# 方法四:手动放置 jar 和 pom 文件
如果无法使用 mvn install:install-file 命令,也可以手动将 jar 和 pom 文件同时放到本地仓库对应目录下。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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-lib</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
</project>
2
3
4
5
6
7
8
9
10
11
注意:手动放置的 POM 文件如果缺少
<dependencies>部分,该依赖的传递依赖不会生效。
# 各种操作的有效性对比
| 操作 | 是否有效 | 原因 |
|---|---|---|
| 手动放 jar 包 | ❌ | 缺少 POM 文件,Maven 无法解析 |
| 手动放 jar + pom | ✅ | 文件完整,Maven 可以识别 |
mvn install:install-file | ✅ | Maven 自动生成完整文件结构(推荐) |
只删除 .lastUpdated 后刷新 | ⚠️ | 如果远程仓库有该依赖则有效,否则仍会失败 |
删除 .lastUpdated + -U 刷新 | ✅ | 强制重新下载,远程仓库有则有效 |
# 最佳实践
- 永远不要手动往本地仓库放文件,始终使用
mvn install:install-file命令安装,Maven 会自动生成所有必要的文件。 - 遇到依赖爆红问题,先批量删除
.lastUpdated文件,再执行mvn clean install -U。 - 如果远程仓库确实没有该依赖,使用
mvn install:install-file安装到本地仓库,或上传到公司私服供团队使用。 - 定期清理
.lastUpdated文件,避免因历史下载失败记录影响后续构建。
# 七、常见问题与最佳实践
# 问题 1:配置了镜像但依赖仍然从中央仓库下载
原因:<mirrorOf> 没有匹配到对应的仓库 ID。
解决:检查 <mirrorOf> 的值是否正确。如果想替代所有仓库,使用 *:
<mirrorOf>*</mirrorOf>
# 问题 2:多个镜像只有第一个生效
原因:Maven 对同一仓库只会使用第一个匹配的镜像。
解决:如果需要从不同镜像获取不同依赖,应为不同仓库配置不同 ID,并分别匹配:
<!-- settings.xml -->
<mirrors>
<mirror>
<id>aliyun-central</id>
<mirrorOf>central</mirrorOf>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
<mirror>
<id>company-mirror</id>
<mirrorOf>company-repo</mirrorOf>
<url>http://mirror.company.com/repository/public/</url>
</mirror>
</mirrors>
2
3
4
5
6
7
8
9
10
11
12
13
<!-- pom.xml -->
<repositories>
<repository>
<id>company-repo</id>
<url>http://nexus.company.com/repository/maven-public/</url>
</repository>
</repositories>
2
3
4
5
6
7
# 问题 3:SNAPSHOT 版本不更新
原因:默认情况下 Maven 对 SNAPSHOT 的更新检查有频率限制。
解决:
- 在
<repository>中配置<updatePolicy>always</updatePolicy> - 或在命令行使用
-U参数强制更新:mvn clean install -U
# 最佳实践总结
| 场景 | 推荐配置 |
|---|---|
| 国内开发,加速中央仓库下载 | <mirrorOf>central</mirrorOf> 配置阿里云镜像 |
| 公司有私服 | 私服配置为 <mirrorOf>*</mirrorOf>,私服内部再代理中央仓库 |
| 需要多个仓库源 | 在 <repositories> 中配置多个仓库,注意 ID 不要重复 |
| SNAPSHOT 频繁更新 | 配置 <updatePolicy>always</updatePolicy> 或使用 -U 参数 |
# 八、依赖解析流程图
┌─────────────┐
│ 需要依赖 X │
└──────┬──────┘
│
▼
┌─────────────────────┐
│ 1. 查找本地仓库 │
└──────────┬──────────┘
│
找到了?│
┌────────┬────────┘
│ 是 │ 否
▼ ▼
使用依赖 ┌───────────────────────────────────┐
│ 2. 遍历 <repositories> 仓库列表 │
│ (含 Super POM 的 central) │
└──────────┬────────────────────────┘
│
▼
┌───────────────────────┐
│ 取下一个仓库 │◄────────────────┐
└──────────┬────────────┘ │
│ │
▼ │
┌───────────────────────┐ │
│ 该仓库有匹配的 <mirror>? │ │
└──────────┬────────────┘ │
有镜像?│ │
┌────────┬───┘ │
│ 是 │ 否 │
▼ ▼ │
┌──────────────┐ ┌──────────────┐ │
│ 访问镜像地址 │ │ 访问原始地址 │ │
└──────┬───────┘ └──────┬───────┘ │
│ │ │
└────────┬───────┘ │
▼ │
找到了?│ │
┌─────┬────┘ │
│是 │否 │
▼ │ │
使用 │ ┌──────────────────┐ │
依赖 │ │ 还有更多仓库吗? │ │
│ └────────┬─────────┘ │
│ │ │
│ 有更多?│ │
│ ┌───┬───┘ │
│ │是 │否 │
│ ▼ ▼ │
│ │ ┌──────────────┐ │
│ │ │ 3. 构建失败 │ │
│ │ │ 抛出异常 │ │
│ │ └──────────────┘ │
│ │ │
└─────┴─────────────────────────────────────┘
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
流程说明:
- Maven 先查找本地仓库,找到则直接使用。
- 本地仓库没有时,Maven 遍历
<repositories>仓库列表(包括 Super POM 中的central)。 - 对每个仓库,先检查是否有匹配的
<mirror>:- 有匹配镜像 → 访问镜像地址(不会访问原始地址)
- 无匹配镜像 → 访问原始地址
- 如果当前仓库(或其镜像)找到了依赖,则使用该依赖。
- 如果当前仓库没找到,则继续尝试下一个仓库。
- 所有仓库都尝试完毕仍未找到,构建失败,抛出异常。