Maven 详解:Java 项目构建与依赖管理工具(从入门到精通)

Apache Maven 是 Java 生态系统中最流行的项目管理和构建自动化工具,通过约定优于配置(Convention Over Configuration)的理念,简化了 Java 项目的生命周期管理(编译、测试、打包、部署等)。

Maven 基于构建生命周期的核心概念。它本质上是一套标准化的、有序的构建步骤集合,定义了从项目源码到可部署工件(如 JAR、WAR 包)的完整过程。这种标准化解决了不同项目构建流程混乱、不一致的问题,让开发者能专注于业务逻辑而非构建细节。


一、Maven 构建生命周期

1、生命周期

生命周期(Lifecycle) 是 Maven 对 “项目处理过程” 的总称,涵盖了从项目初始化、构建、测试、文档生成到部署的所有标准化流程。Maven 中定义了3 个标准生命周期,分别处理不同维度的任务,每个生命周期包含多个阶段(Phase),按顺序执行。

(1)Clean 生命周期

负责清理项目:删除上一次构建生成的文件(如 class 文件、打包产物等),确保构建环境干净。主要阶段(顺序执行):

  • pre-clean:清理前的准备工作(如备份文件)。
  • clean:删除上一次构建生成的目录(默认是target/目录)。
  • post-clean:清理后的收尾工作(如记录清理日志)。
(2)Default 生命周期(核心)

构建项目的主要流程,负责核心构建流程(编译、测试、打包、部署等)。详细可见生命周期参考,常用阶段按执行顺序如下:

  • validate:验证项目是否完整(如检查必要的配置文件、依赖是否存在)。
  • compile:编译项目主源码(将src/main/java下的 Java 文件编译为 class 文件,输出到target/classes)。
  • test :运行单元测试(执行src/test/java下的测试用例,依赖compile阶段)。
  • package :将编译后的 class 文件打包为可分发的工件(如 JAR、WAR,输出到target/目录)。
  • install<:将打包好的工件安装到本地 Maven 仓库(~/.m2/repository),供本地其他项目依赖。
  • deploy:将工件部署到远程 Maven 仓库,供团队其他成员或生产环境使用(依赖install阶段)。

PS:【执行规则】若执行某个阶段,其前面的所有阶段会自动依次执行。例如,执行mvn install时,会自动执行validate → compile → test → package → install

(3)Site 生命周期

负责生成项目文档和站点(如 API 文档、项目说明、测试报告等)。主要阶段(顺序执行):

  • pre-site:生成站点前的准备工作(如收集文档素材)。
  • site:生成站点文档(默认包含 HTML 格式的项目信息、依赖列表等)。
  • post-site:生成站点后的处理(如检查文档完整性)。
  • site-deploy:将生成的站点文档部署到远程服务器(如公司内网的文档服务器)。

示例命令

mvn clean package  # 清理并打包项目
mvn install        # 编译、测试并安装到本地仓库
mvn deploy         # 部署到远程仓库
构建生命周期(Build Lifecycle)

指的是从源码到最终可交付产物的 一系列有序的、固定的阶段 。通常特指上述 3 个生命周期中的Default 生命周期,是 Maven 最核心的部分,直接对应 “从源码到可部署工件” 的构建过程(如编译、打包、安装、部署)。它是 “生命周期” 概念中与 “构建” 最相关的部分。

2、Maven 在生命周期基础上做了什么?

Maven 的核心价值之一在于其标准化的生命周期(Lifecycle),它定义了项目构建的完整流程(如清洁、编译、测试、打包、部署等)。但 Maven 并未止步于“定义生命周期”,而是在此基础上通过一系列机制实现了生命周期的可执行性、可扩展性和标准化,让构建过程更高效、更灵活。

(1)用“插件机制”实现生命周期的具体功能

Maven 的生命周期仅定义了“要做什么”(如“编译”“测试”),但并未实现“怎么做”。真正执行这些操作的是 Maven 插件(Plugin),而 Maven 通过“阶段与插件目标的绑定”将二者关联。

  • 核心逻辑:生命周期的每个阶段(Phase)都绑定了一个或多个插件的“目标(Goal)”,插件目标负责具体的操作。
  • Maven 为常见的构建任务提供了默认插件绑定,例如:
    • default 生命周期的 compile 阶段(编译主代码)绑定了 maven-compiler-plugin:compile 目标;
    • test 阶段(执行测试)绑定了 maven-surefire-plugin:test 目标;
    • package 阶段(打包)绑定了 maven-jar-plugin:jar 目标(Java 项目)。

Maven 允许用户自定义阶段与插件目标的绑定,以扩展生命周期的功能。例如:

  • 默认情况下,package 阶段对 Java 项目生成 JAR 包(通过 maven-jar-plugin),但如果是 Web 项目,可绑定 maven-war-pluginwar 目标,让 package 阶段生成 WAR 包;
  • 还可通过 executions 配置,将自定义插件目标绑定到任意阶段(如在 package 后自动执行代码质量检查插件)。
<build>
  <plugins>
    <!-- SonarQube 代码质量检查插件 -->
    <plugin>
      <groupId>org.sonarsource.scanner.maven</groupId>
      <artifactId>sonar-maven-plugin</artifactId>
      <version>3.9.1.2184</version>
      
      <!-- 自定义执行配置:绑定到 package 阶段之后 -->
      <executions>
        <execution>
          <!-- 执行的唯一标识(可自定义) -->
          <id>sonar-after-package</id>
          
          <!-- 绑定到 package 阶段,会在 package 完成后执行 -->
          <phase>package</phase>
          
          <!-- 指定要执行的插件目标 -->
          <goals>
            <goal>sonar</goal> <!-- SonarQube 插件的核心目标 -->
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

(2)标准化“项目结构”,适配生命周期的执行

为了让生命周期的各个阶段能“准确找到所需资源”,Maven 定义了标准化的项目目录结构,并与生命周期阶段强关联。
例如:

  • 主代码目录 src/main/java 对应 compile 阶段的编译源;
  • 测试代码目录 src/test/java 对应 test-compile 阶段的编译源;
  • 资源文件目录 src/main/resources 对应 process-resources 阶段的资源复制;
  • 约定输出目录为targetcompile 阶段输出到 target/classes/test-compile 阶段输出到 target/test-classes/package 阶段打包生成的 JAR/WAR 等文件会直接存放在 target/ 根目录下等。

这种标准化让生命周期的每个阶段无需手动配置路径,直接按约定找到资源,实现了“约定优于配置”(Convention over Configuration)。

(3)依赖管理:为生命周期提供“资源支持”

生命周期的多个阶段(如编译、测试、运行)都需要依赖外部库(如 JAR 包)。Maven 构建了一个完整的仓库体系,并在生命周期基础上整合了依赖管理机制,自动为各阶段提供所需资源:

  • 依赖自动引入:通过 pom.xml 声明依赖后,Maven 会在 compile 阶段自动从仓库下载依赖,并添加到类路径;
  • 依赖传递与冲突解决:自动处理依赖的传递性(如 A 依赖 B,B 依赖 C,则 A 自动依赖 C),并通过“就近原则”“声明优先”等规则解决版本冲突,确保生命周期各阶段(如编译、测试)能正确引用依赖。

(4)生命周期的“阶段顺序”与“自动触发”

Maven 的生命周期阶段按固定顺序执行,且“前序阶段完成后才会执行后续阶段”。例如:

  • 执行 mvn package(打包)时,Maven 会自动先执行其前序阶段:validateinitializecompiletest-compiletestpackage
  • 不同生命周期相互独立,但可通过命令同时触发(如mvn clean install会先执行clean生命周期的所有阶段,再执行default生命周期到install的阶段)

这种“自动触发”机制避免了手动执行每个阶段的繁琐,确保构建流程的完整性(如打包前必须先通过测试)。

在此基础上,Maven 还支持阶段的部分执行(如只执行 mvn test 跳过打包),兼顾灵活性。

(5)结合“继承与聚合”,支持多模块项目的生命周期管理

在多模块项目中,Maven 的继承(Inheritance)和聚合(Aggregation)机制让生命周期更高效:

  • 继承:子项目可继承父项目的生命周期配置(如插件版本、阶段绑定),避免重复配置;
  • 聚合:通过 modules 声明模块依赖,执行根项目的生命周期阶段(如 mvn install)时,Maven 会按依赖顺序自动执行所有子模块的对应阶段(如先构建被依赖的模块,再构建依赖它的模块)。

二、POM(Project Object Model)

Maven 的核心是 pom.xml 文件,它定义了项目的元数据、依赖、插件和构建配置:

1、pom 文件基本构成

<!-- 根元素是 <project>,所有配置都嵌套在其中。根元素必须声明 Maven 的 XML 命名空间
xmlns="http://maven.apache.org/POM/4.0.0":指定 Maven POM 的版本(当前最新为 4.0.0)。
schemaLocation:指定 XML schema 位置,用于验证 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">
  <!-- 指定 POM 模型版本,必须为 4.0.0(Maven 2/3 通用) -->
  <modelVersion>4.0.0</modelVersion>

  
  <!-- 项目坐标GAV(唯一标识)
  Maven 通过 GroupId、ArtifactId、Version(简称 GAV)唯一标识一个项目,是依赖管理的基础。
  - <groupId>:组织/公司标识(通常用反向域名,如 com.example)。
  - <artifactId>:项目/模块名称(如 user-service)。
  - <version>:项目版本(如 1.0.0、1.0.0-SNAPSHOT,SNAPSHOT 表示快照版本)。
  -->
  <groupId>com.example</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0.0</version>

  <!-- 可选基本信息
   - <name>:项目名称(可读性标识,非唯一)。
   - <description>:项目描述。
   - <url>:项目官方网站地址。
   - <inceptionYear>:项目创建年份。
  -->
  <name>Demo Project</name>
  <description>A sample Maven project</description>
  <url>https://example.com/demo</url>
  <inceptionYear>2025</inceptionYear>
  
  <!-- 依赖管理 -->
  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.3.23</version>
    </dependency>
  </dependencies>

  
  <!-- 构建配置 -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>11</source>
          <target>11</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

2、依赖管理

Maven 通过中央仓库(https://repo.maven.apache.org/maven2)自动下载依赖,支持:

  • 传递依赖:自动解析依赖的依赖(如 spring-core 依赖 commons-logging)。
  • 依赖范围(Scope):控制依赖在不同阶段的可用性(如 compiletestruntime)。
  • 依赖排除:排除不需要的传递依赖(如 exclusions 标签)。

(1)<dependencies>:直接依赖

声明项目运行或编译时需要的具体依赖,Maven 会自动从仓库下载并加入类路径。

<dependencies>
    <!-- 引入 Spring Boot 核心依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.7.0</version>
    </dependency>
    
    <!-- 引入 JUnit 测试依赖(仅测试时生效) -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope> <!-- 依赖范围 -->
    </dependency>
</dependencies>
依赖范围(Scope)

控制依赖在哪些生命周期阶段生效,常用值:

范围编译测试运行打包示例
compileSpring、Hibernate 等
testJUnit、Mockito
runtimeJDBC 驱动(运行时需要)
providedServlet API(容器已提供)
system本地 JAR(需指定路径)

(2)<dependencyManagement>:依赖版本管理

用于统一管理依赖版本,仅声明版本,不实际引入依赖,子项目可通过 groupIdartifactId 继承版本,避免版本冲突。

<!-- 父项目 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.0</version> <!-- 统一版本 -->
        </dependency>
    </dependencies>
</dependencyManagement>
<!-- 子项目引用时无需指定版本 -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId> <!-- 继承父 POM 版本 -->
    </dependency>
</dependencies>

(3)依赖冲突

Maven 会自动引入直接依赖的 “依赖”(即传递依赖),形成依赖树。错误的版本可能导致类找不到(ClassNotFoundException)、方法不兼容等问题。当多个依赖引入同一库的不同版本时,Maven 按以下规则处理:

  1. 路径最短优先:选择依赖树中层级浅的版本(如 A → B → X:1.0A → X:2.0,选 2.0)。
  2. 声明顺序优先:若路径相同,先声明的依赖优先。

当默认规则不符合需求时,需手动干预,常用方法如下:

  1. 排除不需要的依赖(exclusion)

在引入冲突依赖的地方,排除低版本或不兼容的传递依赖。

  • exclusion 不需要指定版本,只需 groupIdartifactId,因为要排除的是该依赖的所有版本。
<!-- 项目依赖 A 和 B,A 引入的 C-1.0 有问题,需排除 C-1.0,保留 B 引入的 C-2.0: -->
<dependencies>
    <!-- 依赖 A,排除其传递的 C-1.0 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>A</artifactId>
        <version>1.0</version>
        <exclusions>
            <exclusion>
                <!-- 必须精确匹配 C 的 groupId 和 artifactId -->
                <groupId>com.example</groupId>
                <artifactId>C</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <!-- 依赖 B,其传递的 C-2.0 会被保留 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>B</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>
  1. 直接声明目标版本(利用最短路径优先)

pom.xml 中直接声明冲突依赖的目标版本,使其成为 “直接依赖”(路径长度为 1),覆盖传递依赖的版本。

  • 适用于:明确知道需要哪个版本,且该版本兼容所有依赖它的库。
<!-- 项目依赖 A 和 B,A 引入的 C-1.0 有问题,需排除 C-1.0,保留 B 引入的 C-2.0: -->
<dependencies>
    <!-- 直接声明 C-2.0,路径长度 1,优先级最高 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>C</artifactId>
        <version>2.0</version>
    </dependency>

    <!-- A 和 B 的依赖照常声明,其传递的 C 会被覆盖 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>A</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>B</artifactId>
        <version>1.0</version>
    </dependency>
</dependencies>
  1. 使用 dependencyManagement 统一版本

在多模块项目中,通过父 POM 的 <dependencyManagement> 统一管理依赖版本,子模块继承后无需重复声明版本,避免冲突。

  • 集中管理版本,修改时只需改父 POM,适用于大型项目。
<!-- 父 POM 配置 -->
<dependencyManagement>
    <dependencies>
        <!-- 统一 C 的版本为 2.0 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>C</artifactId>
            <version>2.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 子模块引用(无需指定版本,自动继承 2.0) -->
<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>C</artifactId> <!-- 版本继承自父 POM 的 dependencyManagement -->
    </dependency>
</dependencies>

3、构建配置

定义项目构建的规则,包括插件配置、资源目录、输出目录等。主要通过pom.xml中的<build>元素实现。<合理的构建配置能自动化完成编译、测试、打包等生命周期阶段的任务。

(1)基础构建配置

<build> 是 Maven 构建配置的根元素,包含全局构建配置和插件配置。

<project>
  <!-- 其他配置…… -->
  <!-- 构建配置 -->
  <build>
    <!-- 输出目录(默认 target/) -->
    <directory>target</directory>
    <!-- 打包后的文件名(不含扩展名) -->
    <finalName>${project.artifactId}-${project.version}</finalName>
    <!-- 源码目录(默认 src/main/java) -->
    <sourceDirectory>src/main/java</sourceDirectory>
    <!-- 测试源码目录(默认 src/test/java) -->
    <testSourceDirectory>src/test/java</testSourceDirectory>
    <!-- 资源文件目录(默认 src/main/resources) -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <!-- 是否过滤资源文件(替换 ${property} 占位符)(默认 true)
            资源文件中的 ${property} 占位符会被 pom.xml 中 <properties> 定义的属性替换(如 ${project.version} 替换为项目版本)。
            -->
            <filtering>true</filtering>
            <!-- 包含/排除特定文件(可选) -->
            <includes>
              <include>*.properties</include>
              <include>*.xml</include>
            </includes>
            <excludes>
              <exclude>*.txt</exclude>
            </excludes>
        </resource>
    </resources>
    
    <!-- 测试资源文件目录 -->
    <testResources>
        <testResource>
            <directory>src/test/resources</directory>
        </testResource>
    </testResources>
    
     <!-- 3. 插件配置 -->
    <plugins>...</plugins>
    <pluginManagement>...</pluginManagement>
  </build>
</project>

(2)插件配置

Maven 通过插件执行具体任务,每个插件包含多个目标(Goal)。<plugins> 用于配置项目使用的插件。

1)基本配置示例:配置编译插件(指定 JDK 版本)
<build>
    <plugins>
        <plugin>
           <!-- 插件坐标(GAV) -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version> <!-- 插件版本 -->
            <configuration>
                <!-- 配置插件参数:指定 JDK 版本 -->
                <source>1.8</source> <!-- 源码兼容版本 -->
                <target>1.8</target> <!-- 编译输出版本 -->
            </configuration>
        </plugin>
    </plugins>
</build>
2)插件目标绑定到生命周期阶段:

通过 <executions> 将插件目标(Goal)绑定到生命周期阶段(Phase):

<plugins>
  <!-- 执行 mvn package 时,会自动触发 javadoc 目标,在 target/docs 生成 API 文档。 -->
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>3.3.1</version>
    
    <!-- 执行配置:绑定目标到阶段 -->
    <executions>
      <execution>
        <id>generate-docs</id> <!-- 唯一标识(自定义) -->
        <phase>package</phase> <!-- 绑定到 package 阶段 -->
        <goals>
          <goal>javadoc</goal> <!-- 执行的插件目标 -->
        </goals>
        <!-- 目标的参数配置(可选) -->
        <configuration>
          <destDir>${project.build.directory}/docs</destDir> <!-- 文档输出目录 -->
        </configuration>
      </execution>
    </executions>
  </plugin>
</plugins>
3)<pluginManagement>:统一管理插件版本

类似 <dependencyManagement>,用于声明插件的版本和默认配置,但不实际启用插件。子项目或当前项目的 <plugins> 中引用插件时,可省略版本,直接继承配置。适用于多模块项目(父 POM 中定义)。

4)常用插件
  • 编译插件maven-compiler-plugin(配置 JDK 版本)。
  • 测试插件maven-surefire-plugin(配置测试框架)。
  • 打包插件maven-jar-plugin(JAR 打包)、maven-war-plugin(WAR 打包)。
  • 资源插件maven-resources-plugin(处理资源文件)。
<!-- 打包插件(maven-jar-plugin),自定义 JAR 包的清单文件 -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <version>3.2.0</version>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath> <!-- 自动添加依赖到类路径 -->
        <mainClass>com.example.DemoMain</mainClass> <!-- 主类(可执行 JAR) -->
      </manifest>
    </archive>
  </configuration>
</plugin>

<!-- 测试插件(maven-surefire-plugin),配置单元测试(如跳过测试、指定测试类) -->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>3.0.0-M5</version>
  <configuration>
    <skipTests>false</skipTests> <!-- 是否跳过测试(true 则不执行测试) -->
    <includes>
      <include>**/*Test.java</include> <!-- 包含的测试类 -->
    </includes>
    <excludes>
      <exclude>**/*IntegrationTest.java</exclude> <!-- 排除的测试类 -->
    </excludes>
  </configuration>
</plugin>

<!-- 资源插件(maven-resources-plugin),处理资源文件-->
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-resources-plugin</artifactId>
  <version>3.3.1</version> 
  <configuration>
    <!-- 资源文件编码(避免中文乱码) -->
    <encoding>UTF-8</encoding>
  </configuration>
  <executions>
    <!-- 配置主资源处理(绑定到 process-resources 阶段) -->
    <execution>
      <id>copy-main-resources</id>
      <phase>process-resources</phase>
      <goals>
        <goal>copy-resources</goal> <!-- 执行复制资源目标 -->
      </goals>
      <configuration>
        <!-- 输出目录(主资源最终位置) -->
        <outputDirectory>${project.build.outputDirectory}</outputDirectory>
        <!-- 自定义主资源目录 -->
        <resources>
          <resource>
            <directory>src/main/config</directory> <!-- 资源源目录 -->
            <includes>
              <include>*.properties</include> <!-- 只包含 properties 文件 -->
              <include>*.xml</include>        <!-- 只包含 xml 文件 -->
            </includes>
            <excludes>
              <exclude>*.txt</exclude>        <!-- 排除 txt 文件 -->
            </excludes>
          </resource>
        </resources>
      </configuration>
    </execution>
   <!-- 配置测试资源处理(绑定到 process-test-resources 阶段) -->
    <execution>
      <id>copy-test-resources</id>
      <phase>process-test-resources</phase>
      <goals>
        <goal>copy-resources</goal>
      </goals>
      <configuration>
        <!-- 测试资源输出目录 -->
        <outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
        <!-- 自定义测试资源目录 -->
        <resources>
          <resource>
            <directory>src/test/config</directory>
            <filtering>true</filtering> <!-- 开启测试资源过滤 -->
          </resource>
        </resources>
      </configuration>
    </execution>
  </executions>
</plugin>

4、属性

Maven 中的 <properties>元素用于定义键值对形式的属性,是项目配置的重要机制。它的核心作用是集中管理可复用的值(如版本号、路径、编码等),提高 pom.xml的可维护性和灵活性。

(1)基本使用

<properties>
    <java.version>1.8</java.version>
    <spring.version>2.7.0</spring.version> <!-- 定义属性:spring版本 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 内置属性:源码编码 -->
</properties>
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version> <!-- 使用属性 -->
  </dependency>
</dependencies>

(2)属性的分类

1)自定义属性

用户在<properties>中手动定义的属性,用于统一管理项目中的可变值(如版本号、路径等)。

2)内置属性(Project Properties)

Maven 预定义的属性,对应项目自身信息,无需手动定义,直接引用即可。常用内置属性:

属性名含义示例值
${project.groupId}项目的 groupIdcom.example
${project.artifactId}项目的 artifactIddemo-project
${project.version}项目的版本1.0.0-SNAPSHOT
${project.name}项目名称(<name>
定义)
Demo Project
${project.basedir}项目根目录(pom.xml
所在目录)
/Users/dev/demo-project
${project.build.directory}构建输出目录(默认 target
/Users/dev/demo-project/target
${project.build.outputDirectory}主类输出目录(默认 target/classes
target/classes
3)Settings 属性

与 Maven 全局配置(settings.xml)相关的属性,格式为 ${settings.xxx},例如:

  • ${settings.localRepository}:本地仓库路径(默认 ~/.m2/repository
  • ${settings.proxies}:代理配置等(较少直接使用)
4)系统属性

Java 系统属性(可通过 java -Dkey=value 传入)和 Maven 运行时的系统属性,例如:

  • ${user.home}:当前用户的主目录
  • ${os.name}:操作系统名称
  • 自定义系统属性:mvn clean package -Denv=prod,在 pom.xml 中通过 ${env} 引用
5)环境变量属性

操作系统的环境变量,通过 ${env.ENV_NAME} 引用(注意:env 前缀固定),例如:

  • ${env.JAVA_HOME}:引用系统的 JAVA_HOME 环境变量
  • ${env.PATH}:引用系统的 PATH 环境变量

(3)注意

  1. 属性名大小写敏感${java.version}${Java.Version} 是不同的属性。
  2. 优先级:系统属性(-D 传入) > 自定义属性 > 内置属性。
  3. 避免循环依赖:属性值不能引用自身或形成循环(如 <a>${b}</a> <b>${a}</b>)。
  4. 继承性:子项目会继承父项目 <properties> 中定义的属性,可在子项目中覆盖。

5、其它

(1)打包类型(<packaging>

指定项目打包后的产物类型,默认 jar

  • jar:Java 项目,打包为 JAR 包。
  • war:Web 项目,打包为 WAR 包。
  • pom:父项目或聚合项目(无代码,仅用于管理)。
  • ear:企业级应用,打包为 EAR 包(少见)。
<packaging>war</packaging>

三、Maven 仓库管理

Maven 通过仓库管理依赖和项目构件。

依赖查找顺序

本地仓库镜像仓库(若配置) → **pom.xml**** 中配置的远程仓库** → 中央仓库(默认)。

1、仓库类型

(1)本地仓库

默认位于 ~/.m2/repository,存储已下载的依赖和本地安装的构件(通过 mvn install 安装)。避免重复下载,加速构建过程。

(2)远程仓库

2、全局配置

在 Maven 全局配置文件中配置,对所有项目生效。settings.xml 有两个位置:

  • 全局:${M2_HOME}/conf/settings.xml(影响所有用户);
  • 用户级:${user.home}/.m2/settings.xml(仅影响当前用户,优先级更高)
<settings>
  <mirrors>
    <!-- 阿里云镜像(优先于中央仓库) -->
    <mirror>
      <id>aliyun-mirror</id>
      <mirrorOf>central</mirrorOf> <!-- 镜像中央仓库 -->
      <name>Aliyun Mirror for Central</name>
      <url>https://maven.aliyun.com/repository/public</url>
    </mirror>

    <!-- 企业私服镜像(镜像所有仓库) -->
    <mirror>
      <id>company-mirror</id>
      <mirrorOf>*</mirrorOf> <!-- * 表示镜像所有仓库 -->
      <url>http://nexus.company.com/repository/maven-public/</url>
    </mirror>
  </mirrors>
  <!-- 若私服需要账号密码,在 servers 中配置认证: -->
  <servers>
    <server>
      <id>company-mirror</id> <!-- 必须与仓库的 <id> 一致 -->
      <username>your-username</username>
      <password>your-password</password>
    </server>
  </servers>
</settings>

其中,<mirrorOf>标签取值:

- `central`:仅镜像中央仓库;
- `repo1,repo2`:镜像指定仓库(多个用逗号分隔);
- `*`:镜像所有仓库(私服常用);
- `!repo1`:镜像除 `repo1` 外的所有仓库。

3、项目级配置

在单个项目的 pom.xml 中配置,仅对当前项目生效。

在 Maven 的 pom.xml不能直接配置私服的认证信息 (用户名 / 密码等校验信息)。Maven 规定,私服的认证信息必须配置在 **settings.xml**中,而pom.xml 仅用于声明仓库地址。

配置依赖仓库(<repositories>):

<repositories>
  <!-- 阿里云仓库(替代中央仓库,国内速度快) -->
  <repository>
    <id>aliyun-public</id> <!-- 仓库唯一标识 -->
    <name>Aliyun Public Repository</name>
    <url>https://maven.aliyun.com/repository/public</url>
    <releases>
      <enabled>true</enabled> <!-- 是否启用发布版本(稳定版) -->
    </releases>
    <snapshots>
      <enabled>false</enabled> <!-- 是否启用快照版本(开发版) -->
    </snapshots>
  </repository>
</repositories>

插件仓库(<pluginRepositories>
插件仓库与依赖仓库分开配置,(格式与 <repositories> 相同):

<pluginRepositories>
    <pluginRepository>
        <id>aliyun-plugin</id>
        <url>https://maven.aliyun.com/repository/public</url>
    </pluginRepository>
</pluginRepositories>

4、发布项目到仓库

通过 mvn deploy 命令可将项目打包后发布到远程仓库(通常是私服),需在 pom.xml 中配置发布地址:

<distributionManagement>
  <!-- 发布发布版本(稳定版)到 releases 仓库 -->
  <repository>
    <id>company-releases</id> <!-- 与 settings.xml 中 server 的 id 一致 -->
    <name>Company Releases Repository</name>
    <url>http://nexus.company.com/repository/maven-releases/</url>
  </repository>

  <!-- 发布快照版本(开发版)到 snapshots 仓库 -->
  <snapshotRepository>
    <id>company-snapshots</id>
    <name>Company Snapshots Repository</name>
    <url>http://nexus.company.com/repository/maven-snapshots/</url>
  </snapshotRepository>
</distributionManagement>
  • 版本号带 -SNAPSHOT 的项目会发布到 <snapshotRepository>,否则发布到 <repository>

四、多模块项目

Maven 支持将大型项目拆分为多个模块,每个模块有独立的 POM,通过父 POM 统一管理。子项目可继承父项目的配置(如依赖版本、插件配置等),减少重复配置。

目录结构:

my-project/
├── pom.xml               # 父 POM
├── module-api/           # API 模块
│   └── pom.xml
├── module-service/       # 服务模块
│   └── pom.xml
└── module-web/           # Web 模块
    └── pom.xml

1、项目继承(Inheritance):复用配置,减少重复

项目继承核心是让子项目复用父项目的配置,避免重复定义(如依赖版本、插件配置、属性等)。

  • 抽取多模块项目的通用配置(如依赖版本、插件、编码格式等)到父项目,子项目直接继承,减少冗余。
  • 统一管理项目版本、依赖版本,避免版本混乱。
(1)可继承的配置项

子项目会自动继承父项目的以下配置(可在子项目中覆盖):

  • groupIdversion(子项目可省略,直接继承);
  • properties(属性);
  • dependencyManagement(依赖版本管理);
  • pluginManagement(插件版本和配置管理);
  • repositoriespluginRepositories(仓库配置);
  • build 中的部分配置(如源码目录、输出目录等)。
(2)实现

父项目 POM:

  • 打包类型为 pom(唯一允许被继承的类型)
  • 定义通用配置(如 dependencyManagementpluginManagementproperties 等)。
<?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>parent-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging> <!-- 父项目必须为 pom 类型 -->
    <name>Parent Project</name>

    <!-- 通用属性(子项目可继承) -->
    <properties>
        <java.version>1.8</java.version>
        <spring.boot.version>2.7.0</spring.boot.version>
    </properties>

    <!-- 统一管理依赖版本(子项目引用时无需指定版本) -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${spring.boot.version}</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>${java.version}</source>
                        <target>${java.version}</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

子项目通过<parent>标签指定父项目,继承其配置:

<parent>
    <groupId>com.example</groupId>
    <artifactId>parent-project</artifactId>
    <version>1.0.0</version>
    <!-- 父项目 pom.xml 路径(默认 ../pom.xml) -->
    <relativePath>../parent/pom.xml</relativePath>
</parent>

<!-- 子项目自身坐标(可省略 groupId 和 version,继承父项目) -->
<artifactId>module-api</artifactId>

<!-- 引用父项目管理的依赖(无需指定版本) -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId> <!-- 版本继承自父项目 -->
    </dependency>
</dependencies>

<!-- 继承父项目的插件配置(无需重复定义版本和基础配置) -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId> <!-- 配置继承自父项目的 pluginManagement -->
        </plugin>
    </plugins>
</build>

2、项目聚合(Aggregation):批量构建多模块

多模块项目中,通过一个 “父项目” 将多个子模块(Module)聚合在一起,实现 “一键构建所有模块”,无需逐个处理子模块。

(1)作用
  • 简化多模块项目的构建流程:执行父项目的 Maven 命令(如 mvn clean install),会自动按依赖顺序构建所有子模块。
  • 明确模块间的关系:父项目作为 “容器”,统一管理子模块。
(2)实现

父项目 pom.xml:通过 <modules> 标签列出所有子模块(子模块的相对路径)。

<?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>parent-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging> <!-- 父项目必须为 pom 类型 -->
    <name>Parent Project</name>

    <!-- 声明子模块(相对路径,指向子模块目录) -->
    <modules>
        <module>module-api</module> <!-- 子模块 1 -->
        <module>module-service</module> <!-- 子模块 2 -->
        <module>module-web</module> <!-- 子模块 3 -->
    </modules>
</project>

子模块的 pom.xm无需特殊配置(可独立构建),通常会放在父项目的子目录中,目录名与<module>标签指定的名称一致。

(3)构建规则
  • 执行父项目的 Maven 命令(如 mvn package)时,Maven 会自动按依赖顺序构建子模块:若 module-web 依赖 module-service,则先构建 module-service,再构建 module-web
  • 子模块可单独构建(进入子模块目录执行 mvn 命令),不影响其他模块。

五、常用命令

1、常用命令

mvn clean                # 清理项目
mvn compile              # 编译源代码
mvn test                 # 运行测试
mvn package              # 打包项目(JAR/WAR)
mvn install              # 安装到本地仓库
mvn deploy               # 部署到远程仓库
mvn dependency:tree      # 查看依赖树
mvn archetype:generate   # 创建项目骨架

2、跳过测试

mvn package -DskipTests        # 不执行测试用例,但编译测试代码
mvn package -Dmaven.test.skip=true  # 不执行测试用例,且不编译测试代码

3、查看依赖树

除了命令行,主流 IDE 提供了更直观的可视化依赖树,如 IntelliJ IDEA 中提供了Show Dependencies,会显示图形化依赖树,冲突依赖会标红。

在项目根目录(pom.xml所在目录)执行以下命令,会打印项目的完整依赖树,包括直接依赖和传递依赖。

mvn dependency:tree

输出:

[INFO] com.example:demo:jar:1.0.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.0:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.7.0:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.7.0:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.0:compile
[INFO] |  |  \- ...
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.7.0:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.3:compile
[INFO] |  |  \- ...
[INFO] |  \- ...
[INFO] \- junit:junit:jar:4.13.2:test
  • 树结构中,+ 表示直接依赖,|\- 表示传递依赖的层级关系;
  • compiletest 等表示依赖范围(<scope>)。

(1)常用参数:过滤和筛选

当项目依赖较多时,可通过参数过滤关键信息,提高分析效率。

1)按依赖名过滤(查找特定依赖)

使用 grep(Linux/Mac)或 findstr(Windows)筛选包含指定 artifactId 的依赖:

# Linux/Mac:查找包含 "jackson" 的依赖
mvn dependency:tree | grep "jackson"

# Windows:查找包含 "jackson" 的依赖
mvn dependency:tree | findstr "jackson"
2)查看依赖冲突

添加 -Dverbose 参数,可显示被排除的冲突依赖(标记为 omitted for conflict with):

mvn dependency:tree -Dverbose

输出:

[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.13.3:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.13.3:compile
[INFO] |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.13.3:compile
[INFO] |  |     \- (com.fasterxml.jackson:jackson-bom:pom:2.13.3:import - omitted for conflict with 2.12.7)
  • 上述示例中,jackson-bom:2.13.32.12.7 冲突,Maven 选择了其中一个版本。
3)按依赖范围过滤

通过 -Dscope 参数仅显示指定范围的依赖(如 testcompile):

# 仅显示 test 范围的依赖
mvn dependency:tree -Dscope=test

(2)导出依赖树到文件

将依赖树输出到文本文件,方便保存和分析:

mvn dependency:tree > dependency-tree.txt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SS上善

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值