Maven入门到放弃

一、Maven简介

Maven概述

Maven 是一个 项目构建与依赖管理工具 ,由 Apache 软件基金会开发。

它最常用于 Java 项目的构建、依赖管理、项目管理与发布

  • 依赖管理工具

  • 构建工具

Maven 的核心理念

Maven 有两个最重要的概念:

  1. POM(Project Object Model,项目对象模型)
    每个 Maven 项目都有一个 pom.xml 文件,用来描述项目的结构、依赖、构建方式。
  2. 仓库(Repository)
    存放项目依赖的 jar 包(例如 Spring、MyBatis 的 jar)。
    Maven 会自动从远程仓库下载依赖并缓存到本地仓库。

Maven 的作用

分类 具体功能 说明
依赖管理 自动下载、更新 jar 包 不需要手动下载依赖,只需声明依赖坐标
项目构建 一键编译、测试、打包、部署 mvn clean package 就能生成可运行文件
项目标准化 统一项目结构与目录规范 所有 Maven 项目结构一致,便于协作
生命周期管理 控制项目从构建到发布的整个流程 compile → test → package → install → deploy
多模块项目管理 管理大型项目的多个子模块 父 POM 统一依赖版本、配置插件
插件扩展 通过插件扩展功能 比如编译、测试、生成文档、代码检查等
仓库管理 支持本地仓库、远程仓库、私服 方便团队共享依赖和发布包

工作原理模型图

二、Maven安装和配置

安装 Maven

下载 Maven

官方下载地址:

https://maven.apache.org/download.cgi

选择版本:

建议使用 Maven 3.9.x(如 3.9.9),兼容性强、性能稳定。

下载 .zip(Windows)或 .tar.gz(Linux / macOS)包。

解压安装

  • 将下载的压缩包解压到任意目录,比如:

    复制代码
    D:\Software\apache-maven-3.9.9
  • 解压后主要目录结构如下:

    复制代码
    apache-maven-3.9.9
    ├── bin           # Maven 命令文件 (mvn.cmd / mvn)
    ├── conf          # 配置文件(settings.xml)
    ├── lib           # 核心类库
    └── LICENSE、NOTICE ...

配置环境变量

新建系统变量

变量名 变量值
MAVEN_HOME D:\Software\apache-maven-3.9.9

编辑系统 Path

Path 中添加:

复制代码
%MAVEN_HOME%\bin

验证配置是否成功

打开 命令提示符 (CMD)PowerShell,输入:

复制代码
mvn -v

若出现如下信息,则说明配置成功

复制代码
Apache Maven 3.9.9 (xxxxx)
Maven home: D:\Software\apache-maven-3.9.9
Java version: 17.0.9, vendor: Oracle Corporation
Default locale: zh_CN, platform encoding: UTF-8

Maven配置

Maven 的全局配置文件是:

复制代码
{MAVEN_HOME}/conf/settings.xml

它主要用于配置:

  • 本地仓库路径;
  • 镜像(国内源);
  • 构建环境(JDK、Profile);
  • 代理、服务器信息等。

配置本地仓库地址

xml 复制代码
<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
                              https://maven.apache.org/xsd/settings-1.0.0.xsd">

  <!-- 本地仓库配置 -->
  <localRepository>D:\maven-repo</localRepository>

  ...
</settings>

配置国内阿里镜像

xml 复制代码
<mirrors>
  <!-- 阿里云 Maven 公共仓库 -->
  <mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>Aliyun Maven</name>
    <url>https://maven.aliyun.com/repository/public</url>
  </mirror>
</mirrors>

配置JDK版本项目构建

xml 复制代码
<profiles>
  <profile>
    <id>jdk-17</id>
    <activation>
      <activeByDefault>true</activeByDefault>
    </activation>
    <properties>
      <maven.compiler.source>17</maven.compiler.source>
      <maven.compiler.target>17</maven.compiler.target>
      <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
    </properties>
  </profile>
</profiles>

完整配置模板

xml 复制代码
<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
                              https://maven.apache.org/xsd/settings-1.0.0.xsd">

  <!-- 本地仓库路径 -->
  <localRepository>D:\maven-repo</localRepository>

  <!-- 镜像配置 -->
  <mirrors>
    <mirror>
      <id>aliyunmaven</id>
      <mirrorOf>*</mirrorOf>
      <name>Aliyun Maven</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>
  </mirrors>

  <!-- JDK 构建配置 -->
  <profiles>
    <profile>
      <id>jdk-17</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
      </properties>
    </profile>
  </profiles>

</settings>

IDEA中配置

打开 Maven 设置

依次点击:

复制代码
File → Settings → Build, Execution, Deployment → Build Tools → Maven

指定 Maven 目录

在右侧面板中找到:

  • Maven home path(Maven 主目录)

    • 选择 自定义 Maven 安装目录,不要使用 IDEA 内置的版本;

    • 点击 ... 选择你本地安装的 Maven 路径,例如:

      复制代码
      D:\apache-maven-3.9.9
  • User settings file(用户配置文件)

    • 选择你修改过的 settings.xml 文件,例如:

      复制代码
      D:\apache-maven-3.9.9\conf\settings.xml
  • Local repository(本地仓库)

    • 如果你在 settings.xml 里已经配置过仓库路径,可以留空;

    • 否则这里可手动指定,例如:

      复制代码
      D:\maven-repo

配置 JDK 构建环境

在:

复制代码
File → Settings → Build, Execution, Deployment → Build Tools → Maven → Importing

设置:

  • JDK for importer :选择你的项目使用的 JDK 版本(例如 17)。
  • VM options for importer:可选,一般留空即可。

验证配置是否成功

打开 IDEA 右侧的 Maven 工具栏,点击刷新按钮:

  • 如果可以正确加载 pom.xml
  • 依赖正常下载;
  • 执行命令无报错;

说明配置成功 。

在 IDEA 中验证 Maven 版本

你可以在 IDEA 终端(Terminal) 中输入:

bash 复制代码
mvn -v

正常输出类似内容:

复制代码
Apache Maven 3.9.9
Maven home: D:\apache-maven-3.9.9
Java version: 17.0.9, vendor: Oracle Corporation

表示环境变量与 IDEA 均已正确识别。

推荐配置小技巧

项目 推荐设置
Maven Wrapper 在多人协作项目中使用 mvnw,避免版本不一致
自动导入 打开 "Import Maven projects automatically"
插件下载慢 使用阿里云镜像(https://maven.aliyun.com/repository/public
依赖缓存 本地仓库尽量设置到固态硬盘,提升构建速度

三、Maven工程

Maven工程的GAVP

GAVP是Maven项目坐标的核心组成部分,用于唯一标识一个Maven项目。

GAVP组成要素:

  1. GroupId (G)
    • 定义:组织或公司标识符
    • 命名规范:通常使用反向域名方式,如 com.example.project
    • 作用:避免不同组织间的命名冲突
  2. ArtifactId (A)
    • 定义:项目或模块的唯一标识符
    • 命名规范:使用小写字母和连字符,如 my-web-app
    • 作用:在同一groupId下唯一标识项目
  3. Version (V)
    • 定义:项目的版本号
    • 命名规范:遵循语义化版本控制,如 1.0.0, 2.1.3-SNAPSHOT
    • 特殊版本:
      • SNAPSHOT:快照版本,表示开发中的不稳定版本
      • RELEASE:发布版本
  4. Packaging §
    • 定义:项目的打包方式
    • 常用值:
      • jar:Java应用程序库(默认值)
      • war:Web应用程序
      • pom:父项目或聚合项目
      • ear:企业级应用程序

Java SE工程

通过IDEA创建

Java Web工程

方式一:手动创建

创建一个java se工程

方式二:Maven Archetype模板创建

org.apache.maven.archetypes:maven-archetype-webapp

Maven工程项目结构

标准目录结构

bash 复制代码
my-project/
├── pom.xml                          # 项目配置文件
├── src/                             # 源代码根目录
│   ├── main/                        # 主代码目录
│   │   ├── java/                    # Java源代码
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── App.java
│   │   ├── resources/               # 资源文件
│   │   │   ├── application.properties
│   │   │   └── log4j.xml
│   │   └── webapp/                  # Web应用文件(Web项目)
│   │       ├── WEB-INF/
│   │       │   └── web.xml
│   │       └── index.jsp
│   └── test/                        # 测试代码目录
│       ├── java/                    # 测试Java源代码
│       │   └── com/
│       │       └── example/
│       │           └── AppTest.java
│       └── resources/               # 测试资源文件
│           └── test.properties
└── target/                          # 构建输出目录(自动生成)
    ├── classes/                     # 编译后的class文件
    ├── test-classes/                # 编译后的测试class文件
    └── my-project-1.0.0.jar         # 打包后的文件

四、Maven工程构建

构建的概念

构建(build) 是把源码、资源、配置等变成可运行/可发布产物(artifact)的过程。常见内容包括:

  • 源码编译(Java → class)
  • 资源拷贝(resources → classpath)
  • 单元测试、集成测试执行
  • 打包(jar/war/zip/...)
  • 生成文档/报告
  • 将产物安装到本地仓库或发布到远程仓库
  • (可选)静态检查、代码覆盖率、签名、发布到生产环境

构建要做到的是自动化、可复现、可验证------同一套构建在任何机器上应输出相同或可预测的产物。

构建的过程

构建的过程包括:

清理 → 编译 → 测试 → 打包 → 安装 → 部署

Maven的生命周期

Maven 构建工程时,会自动执行一系列步骤:

清理 → 编译 → 测试 → 打包 → 安装 → 部署

这整套「步骤顺序」称为 生命周期(Lifecycle)

bash 复制代码
Maven 生命周期
├── clean 生命周期(清理)
│   ├── pre-clean
│   ├── clean
│   └── post-clean
│
├── default 生命周期(构建)
│   ├── validate
│   ├── compile
│   ├── test
│   ├── package
│   ├── install
│   └── deploy
│
└── site 生命周期(生成站点)
    ├── pre-site
    ├── site
    ├── post-site
    └── site-deploy

构建命令

命令类别 命令 功能说明 使用场景
清理命令 mvn clean 清理target目录,删除编译结果 构建前清理旧文件
mvn clean compile 清理后编译源代码 确保全新编译
mvn clean test 清理后运行测试 测试前清理环境
mvn clean package 清理后打包项目 生成干净的包文件
mvn clean install 清理后安装到本地仓库 本地部署新版本
编译命令 mvn compile 编译主源代码 日常开发编译
mvn test-compile 编译测试代码 运行测试前编译
测试命令 mvn test 运行单元测试 验证代码正确性
mvn test -DskipTests 跳过测试执行 快速构建跳过测试
mvn test -Dtest=TestClass 运行指定测试类 调试特定测试
打包命令 mvn package 打包项目(jar/war等) 生成可部署包
mvn package -DskipTests 打包时跳过测试 快速打包
安装命令 mvn install 安装到本地仓库 本地使用构建结果
mvn install -DskipTests 安装时跳过测试 快速本地安装
部署命令 mvn deploy 部署到远程仓库 团队共享构件
mvn deploy -DskipTests 部署时跳过测试 快速远程部署
验证命令 mvn validate 验证项目配置 检查项目完整性
mvn verify 验证构建结果 发布前质量检查
站点命令 mvn site 生成项目文档站点 生成项目文档
mvn site-deploy 部署站点文档 发布项目文档
依赖命令 mvn dependency:tree 显示依赖树 分析依赖关系
mvn dependency:list 列出所有依赖 查看依赖清单
mvn dependency:analyze 分析依赖使用情况 优化依赖配置
帮助命令 mvn --version 显示Maven版本 检查环境配置
mvn --help 显示帮助信息 查看命令用法
mvn help:effective-pom 显示实际生效的POM 调试配置问题

参数选项表

参数 功能说明 使用示例
-DskipTests 跳过测试执行 mvn install -DskipTests
-Dmaven.test.skip=true 跳过测试编译和执行 mvn package -Dmaven.test.skip=true
-P profile 激活指定profile mvn install -P dev
-pl module 构建指定模块 mvn install -pl module1
-am 同时构建依赖模块 mvn install -pl module1 -am
-amd 构建依赖当前模块的模块 mvn install -pl module1 -amd
-o 离线模式 mvn install -o
-U 强制更新快照版本 mvn install -U
-X 显示调试信息 mvn install -X
-q 静默模式 mvn install -q
-T n 并行构建(n为线程数) mvn -T 4 install
-s settings.xml 指定settings文件 mvn -s /path/to/settings.xml

生命周期阶段表

生命周期 阶段 说明
clean pre-clean 清理前准备工作
clean 清理上次构建结果
post-clean 清理后处理工作
default validate 验证项目正确性
compile 编译项目源代码
test 运行测试
package 打包项目
install 安装到本地仓库
deploy 部署到远程仓库
site pre-site 生成站点前准备
site 生成项目站点文档
post-site 生成站点后处理
site-deploy 部署站点文档

这个表格总结了Maven最常用的基础命令和参数,可以帮助开发者快速查找和使用Maven命令。

命令示例:

命令 实际执行的阶段
mvn compile validate → compile
mvn test validate → compile → test
mvn package validate → compile → test → package
mvn install validate → compile → test → package → install
mvn deploy validate → compile → test → package → install → deploy

Maven插件

插件(Plugin)是执行具体构建任务的工具,例如编译、打包、测试等;

每个插件中包含多个 目标(Goal)

插件通过 <plugin> 标签在 pom.xml 中配置;

插件通常与生命周期阶段(phase)绑定。

插件名称 主要目标 (Goal) 功能说明
maven-clean-plugin clean 清理 target 目录(默认绑定到 clean 阶段)
maven-resources-plugin resources:resourcesresources:testResources 处理资源文件(过滤配置、拷贝资源)
maven-compiler-plugin compiler:compilecompiler:testCompile 编译主代码和测试代码
maven-surefire-plugin surefire:test 执行单元测试(JUnit、TestNG)
maven-jar-plugin jar:jar 打包生成 .jar 文件
maven-war-plugin war:war 打包生成 .war 文件(Web 项目)
maven-install-plugin install:install 安装构建结果到本地仓库
maven-deploy-plugin deploy:deploy 部署构建产物到远程仓库
maven-site-plugin site:sitesite:deploy 生成项目报告和站点
maven-dependency-plugin dependency:treecopyanalyze 管理、分析依赖(查看依赖树、拷贝依赖)
maven-shade-plugin shade:shade 生成可执行的"胖包"(包含依赖的 jar)
maven-assembly-plugin assembly:single 打包成指定格式(zip/tar.gz/jar 等)
maven-enforcer-plugin enforce 强制项目规则(如 JDK 版本、依赖冲突)
maven-help-plugin help:effective-pomhelp:effective-settings 查看 Maven 最终解析配置
maven-archetype-plugin archetype:generate 快速创建 Maven 工程骨架
spring-boot-maven-plugin spring-boot:runrepackage Spring Boot 打包与运行(打成可执行 jar)
exec-maven-plugin exec:java 执行 Java 主类(快速运行程序)

通过IDEA可视化构建

  1. 清理项目

路径:Lifecycle → clean

双击即可执行

效果:删除 target 目录,清理旧编译产物。

2.编译项目

路径:Lifecycle → compile

编译 src/main/java 代码

输出:target/classes 目录

3.测试项目

路径:Lifecycle → test

执行所有测试类(src/test/java

插件:maven-surefire-plugin

4.打包项目

路径:Lifecycle → package

根据打包类型生成产物:

  • 普通 Java 项目 → .jar
  • Web 项目 → .war

输出目录:target/your-app-version.jar

  1. 安装项目

路径:Lifecycle → install

将打包结果安装到本地仓库(~/.m2/repository),

供其他项目引用。

6.部署项目

路径:Lifecycle → deploy

上传构建结果到远程仓库(如 Nexus、私服)。

构建插件、命令、生命周期之间的关系

生命周期阶段 默认插件 作用
validate - 验证项目
compile maven-compiler-plugin 编译源码
test maven-surefire-plugin 执行测试
package maven-jar-plugin / maven-war-plugin 打包
install maven-install-plugin 安装到本地仓库
deploy maven-deploy-plugin 部署到远程仓库

五、Mavne依赖管理

依赖的基本配置(GAV 坐标)

Maven 中每个依赖都有唯一坐标:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.3.2</version>
    <scope>compile</scope>
    <optional>false</optional>
</dependency>
标签 含义
<groupId> 组织或公司 ID(类似包名)
<artifactId> 模块名(唯一标识)
<version> 版本号
<scope> 依赖作用范围(Scope)
<optional> 是否参与传递依赖

依赖版本统一管理

当多个子模块共用依赖时,不需要重复声明版本,可统一管理:

父 POM:

xml 复制代码
<properties>
    <spring.version>5.3.23</spring.version>
    <junit.version>5.10.0</junit.version>
    <slf4j.version>1.7.36</slf4j.version>
    <java.version>11</java.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>${junit.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

子模块

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <!-- 不写 version -->
    </dependency>
</dependencies>

Maven 会自动继承版本号。

依赖范围

xml 复制代码
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

Maven依赖范围对比表

依赖范围(Scope) 编译主代码 编译测试 运行测试 打包运行 传递性 典型用途 示例
compile (默认) 项目主代码需要的依赖 Spring Core, Commons Lang
provided 由JDK或容器提供的依赖 Servlet API, JSP API
runtime 运行时需要但编译时不需要的依赖 JDBC驱动, SLF4J实现
test 仅测试时需要的依赖 JUnit, Mockito
system 系统本地依赖(不推荐) 本地jar包
import - - - - - 仅用于dependencyManagement BOM导入

详细说明表

Scope 详细说明 注意事项
compile 默认范围,适用于所有阶段 最常用的范围,会传递给依赖项目
provided 编译和测试时需要,运行时由容器提供 不会传递,不会被打包
runtime 编译时不需要,运行时需要 常用于实现类库
test 仅在测试编译和执行阶段有效 不会传递,不会影响主代码
system 类似provided,但需要指定本地路径 Maven 3.9+已废弃,强烈不推荐使用
import 仅用于dependencyManagement,导入BOM 只能与type=pom一起使用

传递性依赖规则表

直接依赖Scope 传递性依赖Scope
compile 保持原样
provided provided
runtime runtime
test 不传递
system 不传递

使用场景对照表

场景 推荐Scope 说明
主要业务逻辑依赖 compile 如Spring框架、工具类库
Web容器API provided 如Servlet API、JSP API
数据库驱动 runtime 编译时不需要,运行时必需
测试框架 test 仅在测试时使用
本地jar包 system(不推荐) 应该安装到本地仓库
BOM导入 import 在dependencyManagement中使用

排除依赖

当某个传递依赖版本冲突或不需要时,可使用 <exclusions> 排除:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

常用依赖命令

命令 说明
mvn dependency:list 查看依赖列表
mvn dependency:tree 查看依赖树
mvn dependency:analyze 分析依赖使用情况
mvn dependency:resolve 强制解析依赖
mvn dependency:purge-local-repository 清除本地缓存重新下载

build构建配置

xml 复制代码
<build>
    <!-- 项目构建的基础目录 -->
    <directory>target</directory>
    
    <!-- 构建后的最终文件名 -->
    <finalName>${artifactId}-${version}</finalName>
    
    <!-- 主源码目录 -->
    <sourceDirectory>src/main/java</sourceDirectory>
    
    <!-- 脚本源码目录 -->
    <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
    
    <!-- 测试源码目录 -->
    <testSourceDirectory>src/test/java</testSourceDirectory>
    
    <!-- 输出目录 -->
    <outputDirectory>target/classes</outputDirectory>
    
    <!-- 测试输出目录 -->
    <testOutputDirectory>target/test-classes</testOutputDirectory>
    
    <!-- 资源配置 -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>false</filtering>
            <targetPath>.</targetPath>
        </resource>
    </resources>
    
    <!-- 测试资源配置 -->
    <testResources>
        <testResource>
            <directory>src/test/resources</directory>
        </testResource>
    </testResources>
    
    <!-- 插件配置 -->
    <plugins>
        <!-- 插件配置 -->
    </plugins>
    
    <!-- 插件管理 -->
    <pluginManagement>
        <!-- 插件版本管理 -->
    </pluginManagement>
</build>

六、Maven依赖传递和依赖冲突

什么是依赖传递

依赖传递 是指:当一个 Maven 项目依赖另一个项目时,

它会自动获取该项目的依赖(间接依赖),不需要在 pom.xml 中手动声明。

复制代码
A 依赖 B  
B 依赖 C

则:

  • A 直接依赖 B(direct dependency)
  • B 直接依赖 C
  • A 间接依赖 C(transitive dependency)

最终 A 的依赖树中会包含:

复制代码
A
 ├─ B
 └─ C

依赖传递特性

特性 说明 示例
自动继承特 依赖 A 时,自动继承其传递依赖 B、C A→B→C,A 自动获得 C
多层传递特性 传递可多级链式传播 A→B→C→D
有效性受作用域限制 不同 scope 影响是否传递 test 不传递
可控性(可排除) 可使用 <exclusions> 阻断不想要的依赖 手动排除某个 jar

依赖传递的作用范围

直接依赖 Scope 传递依赖 Scope 最终在项目中的 Scope
compile compile compile
compile runtime runtime
runtime compile runtime
runtime runtime runtime
test 任意 ❌ 不传递
provided 任意 ❌ 不传递

规则总结一句话:

testprovided 不传递;

其余遵循"较小权限优先"(compile > runtime)

什么是依赖冲突

当多个依赖(直接或间接)引用了同一个库(相同 groupId + artifactId)但版本不同,Maven 无法同时使用多个版本,就必须"选择"其中一个版本加载。这个"选择"过程称为 依赖冲突解析

依赖冲突的表现

现象 原因
⚠️ 类缺失(ClassNotFoundException 使用了被排除或未加载的版本
⚠️ 方法缺失(NoSuchMethodError 加载了不兼容版本
⚠️ 编译成功但运行报错 不同依赖加载的 jar 版本不一致
⚠️ 体积膨胀、打包重复 多版本 jar 同时打包

依赖冲突的特性

特性 说明
1️⃣ 传递性特征 冲突常源于"传递依赖",不是直接依赖
2️⃣ 同名唯一特征 相同 groupId + artifactId 的依赖只能保留一个版本
3️⃣ 自动裁剪特征 Maven 会自动根据规则选择一个版本加载
4️⃣ 非对称特征 冲突解决结果与依赖路径和声明顺序有关,不是随机的

依赖冲突产生的常见场景

多路径依赖

复制代码
A → B → X:1.0
A → C → X:2.0

Maven 必须在 1.0 与 2.0 中择一。

间接依赖传递不同版本

复制代码
A → B(依赖 commons-io:2.5)
  → C(依赖 commons-io:2.8)

父子模块依赖不同版本

复制代码
parent → commons-lang3:3.9
child → commons-lang3:3.12.0

插件自带依赖版本不同

复制代码
maven-compiler-plugin 使用 javax.annotation:1.3
项目使用 javax.annotation:1.2

Maven 的冲突解决原则

Maven 使用两步决策机制解决依赖冲突:

规则一:最短路径优先

在依赖树中,路径层级更浅(距离项目更近)的依赖版本优先。

示例:

复制代码
A
├── B → X:1.0
└── C → D → X:2.0

结果:使用 X:1.0(路径更短)


规则二:先声明优先

当路径长度相同时,先在 pom.xml 中声明的依赖优先

示例:

复制代码
<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>B</artifactId> <!-- B → X:1.0 -->
    </dependency>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>C</artifactId> <!-- C → X:2.0 -->
    </dependency>
</dependencies>

结果:X:1.0 被使用,因为 B 在 C 之前声明。

解决依赖冲突的常用方法

方法 用途 示例
明确声明版本(直接依赖覆盖) 手动指定最终生效版本 <dependency><version>2.0</version></dependency>
使用 <dependencyManagement> 统一版本 父模块集中控制依赖版本 在 parent 中定义版本,子模块不写版本
使用 <exclusions> 排除冲突依赖 从特定依赖中移除冲突项 <exclusion>
使用 <optional>true</optional> 阻止依赖被传递给下游 在被依赖模块中设置
使用 mvn dependency:tree 查看并分析依赖树 识别冲突来源
使用 mvn dependency:analyze 检测未使用/重复依赖 清理多余依赖

七、Maven工程继承和聚合关系

继承关系(父子工程)

目的:解决多模块项目中的配置重复问题。比如,所有模块都使用相同的Spring Boot版本、JUnit版本等。如果在每个模块的POM中都单独定义,会导致版本不一致和维护困难。

关键元素

  • 父POM 中:使用 <dependencyManagement><pluginManagement>声明依赖和插件的版本。
  • 子POM 中:通过 <parent> 元素指向父POM。子模块在声明依赖时,如果该依赖在父POM的<dependencyManagement>中已定义,则可以省略版本号,Maven会自动从父POM继承。

示例

父工程 (parent-project/pom.xml)

xml 复制代码
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>parent-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging> <!-- 必须是pom -->

    <!-- 依赖管理:这里只声明版本,不实际引入依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.7.0</version> <!-- 统一管理版本 -->
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 插件管理 -->
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>2.7.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

子模块 (parent-project/child-module/pom.xml)

xml 复制代码
<project>
    <modelVersion>4.0.0</modelVersion>

    <!-- 声明父工程 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>parent-project</artifactId>
        <version>1.0.0</version>
        <!-- 可选 -->
        <relativePath>../pom.xml</relativePath> <!-- 父工程路径 -->
    </parent>

    <artifactId>child-module</artifactId>
    <!-- 不需要定义groupId和version,默认从父POM继承 -->

    <!-- 引入依赖,无需写版本号,版本由父POM的dependencyManagement决定 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- 引用同一父项目下的其他模块 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>myproject-common</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>
</project>

子项目会继承父项目的:

  • <properties> 属性
  • <dependencyManagement> 依赖管理
  • <build> 插件管理
  • <repositories> 仓库配置
  • <reporting> 报告配置

但不会继承:

  • <modules> 模块声明
  • <dependencies> 中的直接依赖(除非在 dependencyManagement 中定义)

聚合关系( 聚合工程)

目的 :将多个模块组合在一起,以便通过一个命令统一构建。你不需要分别进入每个模块目录去执行mvn命令。

关键元素

  • 聚合POM 中:使用 <modules> 来列出所有需要被一起构建的模块。

示例

聚合工程 (aggregator-project/pom.xml)

xml 复制代码
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>aggregator-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging> <!-- 必须是pom -->

    <!-- 声明要聚合的模块 -->
    <modules>
        <module>module-a</module>
        <module>module-b</module>
        <module>module-c</module>
    </modules>
</project>

项目目录结构:

bash 复制代码
aggregator-project/
├── pom.xml           <-- 聚合POM
├── module-a/
│   └── pom.xml      <-- 模块A(可以有自己的父POM,不一定是这个聚合POM)
├── module-b/
│   └── pom.xml
└── module-c/
    └── pom.xml

当你在 aggregator-project 目录下执行 mvn clean install 时,Maven会按照**反应堆(Reactor)**计算的顺序(考虑模块间的依赖关系)依次构建 module-a, module-b, module-c

最常见的场景:二者合一

在标准的Maven多模块项目中,最常用的模式是让顶层POM同时充当父POM和聚合POM

示例 (root-project/pom.xml)

xml 复制代码
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>root-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging> <!-- 关键! -->

    <!-- 1. 作为聚合工程:声明模块 -->
    <modules>
        <module>core-service</module>
        <module>web-app</module>
        <module>data-access</module>
    </modules>

    <!-- 2. 作为父工程:统一管理依赖和插件 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.7.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <properties>
        <java.version>11</java.version>
    </properties>
</project>

在这种模式下:

  • 你在根目录执行 mvn clean install,Maven会按顺序构建所有子模块(聚合的功能)。
  • 所有子模块通过 <parent> 指向这个根POM,从而继承依赖版本、Java版本等配置(继承的功能)。
  • 子模块之间还可以相互引用依赖。

在实际应用中,将它们结合使用是最高效和标准的做法。

八、Profiles多环境配置

  • 不同环境(dev/test/prod)使用不同依赖和配置
  • 激活方式:命令行参数、系统属性、操作系统等

什么是 Maven Profiles

Profile 是 Maven 提供的一个机制,

用于在不同的 构建环境(Environment) 下,使用不同的配置项,比如:

  • 不同环境的数据库配置;
  • 不同的依赖或插件版本;
  • 不同的构建参数;
  • 不同的打包方式。

简单理解:Maven Profiles = 多环境配置模板

类似于:Spring Boot 的 application-dev.ymlapplication-prod.yml


为什么要用 Profiles

开发场景举例:

环境 数据库 部署路径 备注
开发环境(dev) localhost:3306/test 本地 调试使用
测试环境(test) 10.0.0.12:3306/test 测试服务器 测试团队使用
生产环境(prod) rds.aliyun.com:3306/prod 云服务器 实际部署

使用 profiles,你可以:

  • 在一个 pom.xml 中维护多种环境配置;
  • 使用命令行一键切换;
  • 避免每次打包都手动改配置。

Profiles 的基本结构

pom.xml 中添加 <profiles> 节点:

复制代码
<profiles>
    <!-- 开发环境 -->
    <profile>
        <id>dev</id>
        <properties>
            <env>development</env>
            <db.url>jdbc:mysql://localhost:3306/dev_db</db.url>
            <db.username>root</db.username>
            <db.password>123456</db.password>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
    </profile>

    <!-- 测试环境 -->
    <profile>
        <id>test</id>
        <properties>
            <env>test</env>
            <db.url>jdbc:mysql://10.0.0.12:3306/test_db</db.url>
            <db.username>test</db.username>
            <db.password>123456</db.password>
        </properties>
    </profile>

    <!-- 生产环境 -->
    <profile>
        <id>prod</id>
        <properties>
            <env>production</env>
            <db.url>jdbc:mysql://rds.aliyun.com:3306/prod_db</db.url>
            <db.username>admin</db.username>
            <db.password>******</db.password>
        </properties>
    </profile>
</profiles>

激活 Profiles 的几种方式

方式1:命令行激活(最常用)

复制代码
mvn clean package -Pdev
mvn clean package -Ptest
mvn clean package -Pprod

方式2:默认激活

通过:

复制代码
<activation>
    <activeByDefault>true</activeByDefault>
</activation>

设置默认激活的 profile。

方式3:通过系统属性激活

复制代码
<activation>
    <property>
        <name>env</name>
        <value>dev</value>
    </property>
</activation>

然后执行:

复制代码
mvn clean install -Denv=dev

方式4:通过操作系统属性激活

复制代码
<activation>
    <os>
        <name>Windows 10</name>
    </os>
</activation>

适合针对不同操作系统(Windows/Linux)使用不同的配置。


properties 中使用 Profile 变量

例如在 src/main/resources/config.properties 中引用:

复制代码
db.url=${db.url}
db.username=${db.username}
db.password=${db.password}

Maven 在构建时会自动用当前激活的 Profile 的属性值进行替换。


与 settings.xml 的配合使用

除了项目 pom.xml,你也可以在用户级的 settings.xml(通常在 ~/.m2/ 目录)中配置全局 Profile。

复制代码
<settings>
  <profiles>
    <profile>
      <id>aliyun</id>
      <repositories>
        <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>
    </profile>
  </profiles>

  <activeProfiles>
    <activeProfile>aliyun</activeProfile>
  </activeProfiles>
</settings>

👉 这个 profile 会自动启用,不需要在命令行输入 -Paliyun


Profiles 与打包结合

Profiles 不仅能定义属性,还能定义不同环境的打包行为。例如:

复制代码
<profile>
    <id>prod</id>
    <build>
        <finalName>myapp-prod</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

打包命令:

复制代码
mvn clean package -Pprod

生成的文件名为 myapp-prod.jar


Profiles 与多模块项目结合

在多模块项目中,Profiles 通常定义在父工程中,用于统一控制所有子模块的环境配置。

父 POM:

复制代码
<profiles>
    <profile>
        <id>test</id>
        <modules>
            <module>common</module>
            <module>service</module>
            <module>web</module>
        </modules>
    </profile>
</profiles>

执行:

复制代码
mvn clean package -Ptest

即可在测试环境下一次构建所有模块。

九、Maven私服

Maven私服简介

Maven 私服 是一种中间仓库

位于开发者与远程中央仓库(Maven Central)之间。

它的主要作用是:

  • 代理远程中央仓库,加速依赖下载;
  • 缓存依赖(避免重复下载);
  • 存放公司内部私有 jar;
  • 统一依赖版本管理;
  • 提高构建速度与安全性。

Maven 仓库的类型

仓库类型 说明
本地仓库 每个开发者电脑上的仓库(默认在 ~/.m2/repository
远程仓库 Maven 官方或第三方托管的仓库(如 Maven Central)
私服(私有仓库) 公司或团队内部搭建的代理仓库(如 Nexus、Artifactory)

私服相当于一个中转站

复制代码
开发者 → 私服 → 远程中央仓库

常见的私服产品

工具 开源 企业支持 特点
Sonatype Nexus Repository 使用最广泛,配置简单,性能稳定
JFrog Artifactory 支持多语言(Maven/NPM/Docker 等)
Apache Archiva 较老,社区维护少

目前企业几乎都使用 Nexus 3.x+ ,所以以下讲解基于 Nexus 私服

Nexus下载安装

Nexus Repository Manager 是由 Sonatype 开发的 仓库管理工具,用于:

  • 管理 Maven、npm、Docker 等多种依赖包;
  • 搭建公司内部的 Maven 私服;
  • 代理中央仓库,加速依赖下载
  • 托管内部开发产物,方便共享与版本管理。

下载地址

前往 Sonatype 官网:

https://help.sonatype.com/repomanager3/download

选择 Nexus Repository OSS 版本(免费开源版)下载。

例如:

复制代码
nexus-3.68.1-01-unix.tar.gz

解压与目录说明

复制代码
# Linux / Mac
tar -zxvf nexus-3.68.1-01-unix.tar.gz -C /usr/local/
cd /usr/local/nexus-3.68.1-01

# Windows
解压到 D:\nexus\

目录结构:

复制代码
nexus-3.68.1-01/
├── bin/                # 启动脚本目录
│   ├── nexus           # Linux 启动脚本
│   └── nexus.exe       # Windows 启动脚本
├── etc/                # 配置文件目录
├── lib/                # 依赖库目录
├── public/             # 静态资源目录
└── sonatype-work/      # Nexus 工作目录(仓库存储区)

修改数据存储路径(可选)

默认工作目录为 ../sonatype-work/nexus3

你也可以修改:

复制代码
vi bin/nexus.vmoptions

找到:

复制代码
-Dkaraf.data=../sonatype-work/nexus3

修改为你希望的路径,比如:

复制代码
-Dkaraf.data=/data/nexus-data

启动 Nexus

Linux / Mac

复制代码
cd /usr/local/nexus-3.68.1-01/bin
./nexus start

Windows

双击:

复制代码
nexus.exe /run

或命令行执行:

复制代码
nexus.exe /run

访问 Web 界面

默认端口:8081

浏览器访问:

http://localhost:8081

首次访问需要输入初始密码。


初始管理员账号密码

默认用户名:

复制代码
admin

密码文件位置:

复制代码
sonatype-work/nexus3/admin.password

打开文件复制其中的字符串作为初始密码。

首次登录后会要求你:

  • 修改密码;
  • 设置匿名访问;
  • 配置仓库类型。

在 Maven 中配置 Nexus 私服

编辑 settings.xml(位于 Maven 安装目录的 conf 下或用户目录 ~/.m2/settings.xml):

xml 复制代码
<mirrors>
  <mirror>
    <id>nexus-public</id>
    <mirrorOf>*</mirrorOf>
    <url>http://localhost:8081/repository/maven-public/</url>
  </mirror>
</mirrors>

<servers>
  <server>
    <id>nexus-releases</id>
    <username>admin</username>
    <password>你的密码</password>
  </server>
  <server>
    <id>nexus-snapshots</id>
    <username>admin</username>
    <password>你的密码</password>
  </server>
</servers>

然后在项目的 pom.xml 中添加:

xml 复制代码
<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>

验证是否成功

执行:

复制代码
mvn clean install

查看是否从 Nexus 仓库下载依赖(控制台会出现 nexus 的下载链接)。

上传测试:

复制代码
mvn deploy

构建的包会被上传到 Nexus 的 Hosted 仓库中。

Nexus 私服架构图

Nexus 中仓库类型

仓库类型 说明 举例
proxy(代理仓库) 代理远程中央仓库或第三方仓库 代理 Maven Central
hosted(宿主仓库) 存放内部发布的 jar 包 公司自研模块、内部工具类
group(组合仓库) 将多个仓库聚合为一个统一访问入口 将 hosted + proxy 组合

十、与 CI/CD 集成

  • Maven 与 Jenkins 的自动化构建流程
  • 使用 mvn deploy 发布构件到服务器

CI/CD 与 Maven 的关系

名称 作用
Maven 项目构建工具,负责编译、测试、打包、部署
Jenkins 持续集成/持续部署(CI/CD)工具,自动化执行 Maven 构建
Nexus 构件仓库,用于存放 Maven 构建的 jar/war 包
Git 代码版本管理系统,Jenkins 从 Git 拉取代码

简单来说:

Jenkins 自动拉取 Git 代码 → 调用 Maven 进行构建测试 → 打包产物(jar/war)→ mvn deploy 发布到 Nexus 或服务器。

Maven 与 Jenkins 的自动化构建流程图

相关推荐
番茄Salad2 天前
Spring Boot项目中Maven引入依赖常见报错问题解决
spring boot·后端·maven
夫唯不争,故无尤也3 天前
Maven创建Java项目实战全流程
java·数据仓库·hive·hadoop·maven
weixin_404551243 天前
openrewrite Maven plugin configuration
java·maven·configuration·openrewrite
FIavor.3 天前
Cannot resolve plugin org.apache.maven.plugins:maven-jar-plugin:3.2.2 这怎么办
maven·apache·jar
zjjuejin4 天前
Maven 云原生时代面临的八大挑战
java·后端·maven
摆烂且佛系5 天前
IDEA Maven 仓库配置优先级
github·maven·intellij-idea
momo_via5 天前
maven下载与安装及在IDEA中配置maven
java·maven·intellij-idea
李贺梖梖5 天前
Maven 设置项目编码,防止编译打包出现编码错误
java·maven
洛克大航海5 天前
Ubuntu安装JDK与Maven和IntelliJ IDEA
ubuntu·jdk·maven·intellij idea