Maven是一个项目管理和构建自动化工具,主要服务于基于Java的项目。它使用一个名为POM(Project Object Model)的XML文件来描述项目的构建过程、依赖、插件等信息。
肖哥弹架构 跟大家“弹弹” 高并发锁, 关注公号回复 'mvcc' 获得手写数据库事务代码
欢迎 点赞,关注,评论。
关注公号Solomon肖哥弹架构获取更多精彩内容
历史热点文章
- 解锁大语言模型参数:零基础掌握大型语言模型参数奥秘与实践指南
- 高性能连接池之HikariCP框架分析:高性能逐条分解(架构师篇)
- 缓存雪崩/穿透/击穿/失效原理图/14种缓存数据特征+10种数据一致性方案
- Java 8函数式编程全攻略:43种函数式业务代码实战案例解析(收藏版)
- 一个项目代码讲清楚DO/PO/BO/AO/E/DTO/DAO/ POJO/VO
- 17个Mybatis Plugs注解:Mybatis Plugs插件架构设计与注解案例(必须收藏)
0、本节范围
1、maven 命令规则与实战
1.1 mvn 语法结构
Maven 的命令行语法基于一个简单的结构,允许你执行各种构建和依赖管理任务。以下是 Maven 命令的基本语法结构:
mvn [options] [<goal(s)>] [<phase(s)>]
各部分解释:
[options]
: 可选参数,用于修改 Maven 命令的行为。例如,-U
用于更新依赖,-X
用于调试。[<goal(s)>]
: Maven 插件的目标。这指定了要执行的任务,例如compile
、test
、install
等。[<phase(s)>]
: Maven 构建生命周期的阶段。Maven 会按照生命周期的阶段顺序执行任务,但你也可以指定特定的阶段来执行。
下是这些参数的一些常见值和选项:
[options]
- Maven 命令行选项
Maven 命令行选项用于修改 Maven 的行为。这些选项通常以 -D
或 -U
等形式出现:
-U
,--update-snapshots
: 强制检查并更新项目的快照依赖。-X
,--debug
: 运行 Maven 在调试模式下,提供详细的调试信息。-e
,--error-stack
: 打印错误栈信息。-ff
,--fail-fast
: 在第一个构建失败时停止构建。-q
,--quiet
: 仅打印错误信息。-T
,--thread
: 指定构建时使用的线程数。-Dproperty=value
: 设置一个属性值。-P
,--profile
: 指定要激活的 Maven 配置文件。
[<goal(s)>]
- Maven 插件目标
Maven 插件目标定义了要执行的具体任务。这些目标由 Maven 插件提供,例如 compile
、test
等:
clean
: 清理构建产物。compile
: 编译源代码。test
: 运行测试。install
: 安装构建产物到本地仓库。deploy
: 将构建产物部署到远程仓库。site
: 生成项目文档和报告。jar:jar
: 创建 JAR 文件。war:war
: 创建 WAR 文件。
除了这些核心目标,还有许多其他目标由各种 Maven 插件提供。例如:
maven-compiler-plugin:compile
: 使用编译插件编译 Java 代码。maven-surefire-plugin:test
: 使用 Surefire 插件运行单元测试。maven-jar-plugin:jar
: 使用 JAR 插件创建 JAR 文件。maven-war-plugin:war
: 使用 WAR 插件创建 WAR 文件。
[<phase(s)>]
- Maven 构建生命周期阶段
Maven 构建生命周期阶段定义了 Maven 在构建过程中的各个阶段:
validate
: 验证项目可以被构建。initialize
: 初始化构建。generate-sources
: 生成源代码。process-sources
: 处理源代码。generate-resources
: 生成资源文件。process-resources
: 复制并处理资源文件到目标目录。compile
: 编译项目的源代码。process-classes
: 处理编译生成的类文件。generate-test-sources
: 生成测试源代码。process-test-sources
: 处理测试源代码。generate-test-resources
: 生成测试资源。process-test-resources
: 复制并处理测试资源文件到目标目录。test-compile
: 编译测试源代码。process-test-classes
: 处理测试编译生成的类文件。test
: 运行测试。prepare-package
: 准备打包。package
: 将编译的代码打包成 JAR、WAR 或其他格式。pre-integration-test
: 在集成测试执行之前准备。integration-test
: 执行集成测试。post-integration-test
: 集成测试执行之后的工作。verify
: 验证包是否符合质量标准。install
: 安装包到本地仓库。deploy
: 将最终的包部署到远程仓库。
这些阶段反映了 Maven 的标准构建生命周期,每个阶段都可以执行一系列预定义的任务。
1.2 mvn 常用命令
1.2.1. 构建项目
mvn clean
: 清理项目,删除target
目录。mvn compile
: 编译项目的源代码。mvn test
: 运行单元测试。mvn package
: 打包项目。mvn verify
: 运行所有检查,确保项目可以部署。mvn install
: 安装项目到本地仓库。mvn deploy
: 将项目部署到远程仓库。
1.2.2. 生成项目报告
mvn site
: 生成项目报告。mvn javadoc:javadoc
: 生成 JavaDoc 文档。mvn surefire-report:report
: 生成测试报告。
1.2.3. 项目信息
mvn dependency:tree
: 显示项目的依赖树。mvn dependency:list
: 列出项目的所有依赖。mvn archetype:generate
: 生成一个新的 Maven 项目。
1.2.4. 项目配置
mvn versions:display
: 显示项目的版本信息。mvn versions:use
: 升级或降级项目的依赖版本。
1.2.5. 运行和管理
mvn exec:java
: 运行主类。mvn tomcat7:run
: 运行项目在 Tomcat 服务器上。mvn jetty:run
: 运行项目在 Jetty 服务器上。
1.2.6. 其他
mvn help:effective-pom
: 显示项目的有效的 POM。mvn help:describe
: 描述一个 Maven 目标。mvn enforcer:enforce
: 执行 Maven 强制规则。
1.2.7. Maven 插件命令
每个 Maven 插件可以提供自己的目标(goals),你可以通过 mvn <groupId>:<artifactId>:<goal>
格式调用它们。
案例
要获取 Maven 项目中所有可用命令的列表,你可以使用以下命令:
mvn help:describe -Dcmd=list
要获取特定 Maven 插件的可用目标列表,可以使用:
mvn <groupId>:<artifactId>:help
例如,要获取 maven-compiler-plugin
的帮助信息,可以使用:
mvn org.apache.maven.plugins:maven-compiler-plugin:help
1.3 mvn 命令格式
Maven 命令格式说明
- Maven 命令: 执行 Maven 构建的工具。
- [options] : Maven 命令行选项,用于修改 Maven 的行为(例如
-U
,-X
)。 - [goal] : Maven 插件的目标。
- [phase] : Maven 构建生命周期的阶段。
- [plugin-group] : Maven 插件的组ID。
- [plugin-artifact] : Maven 插件的项目ID。
- [plugin-version] : Maven 插件的版本。
- [plugin-goal] : 要执行的 Maven 插件目标。
- project coordinates: 项目坐标,包括 groupId、artifactId、version,以及可选的分类器(Classifier)。
案例
一个完整的 Maven 命令可能看起来像这样:
mvn org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile -DskipTests
mvn
: Maven 命令。org.apache.maven.plugins
: 插件的 groupId。maven-compiler-plugin
: 插件的 artifactId。3.8.1
: 插件的 version。compile
: 要执行的插件目标(goal)。-DskipTests
: 一个命令行选项,用来跳过测试。
或者,对于 Maven 内置的生命周期阶段,命令可能更简单:
mvn clean install
clean
: 生命周期的阶段,相当于执行mvn clean:clean
。install
: 另一个生命周期的阶段。
这个结构图提供了 Maven 命令的详细视图,展示了 Maven 命令的各个组成部分和它们之间的关系,并使用了不同的颜色来区分各个部分。
1.4 mvn 命令特殊格式
为什么有时有冒号,有时没有?
- 没有冒号: 当你只指定
<goal>
时,通常不需要冒号。这种情况通常发生在该<goal>
属于一个在 Maven 中已经通过<groupId>
和<artifactId>
定义的插件时。 - 有冒号: 当你需要指定完整的插件坐标(
<groupId>:<artifactId>:<goal>
)时,冒号用于分隔这些部分。
案例说明
- mvn clean: 这个命令使用
maven-clean-plugin
插件的clean
目标。因为clean
目标是 Maven 核心插件的一部分,所以不需要指定完整的坐标。 - mvn compile: 类似于
mvn clean
,这个命令使用maven-compiler-plugin
插件的compile
目标。 - mvn test: 这个命令执行
maven-surefire-plugin
插件的test
目标。 - mvn package: 使用
maven-jar-plugin
插件的jar
目标。 - mvn verify****: 这个命令通常与
maven-invoker-plugin
一起使用,用于验证构建。 - mvn install: 使用
maven-install-plugin
插件的install
目标。 - mvn deploy: 使用
maven-deploy-plugin
插件的deploy
目标。
插件特定的命令
对于不是 Maven 核心插件的命令,你需要指定完整的插件坐标。例如:
- mvn exec:java: 这里
exec
是artifactId
,java
是<goal>
,所以需要冒号分隔。 - mvn tomcat7:run: 这里
tomcat7
是artifactId
,run
是<goal>
,所以需要冒号分隔。 - mvn jetty:run: 这里
jetty
是artifactId
,run
是<goal>
,所以需要冒号分隔。
总结
- 如果命令是 Maven 核心命令或广泛使用的标准插件的一部分,你通常不需要冒号。
- 如果命令是特定插件的一部分,特别是当插件不是 Maven 核心插件时,你需要使用冒号来分隔
<groupId>
、<artifactId>
和<goal>
。
2、maven 多模块设计
2.1 多模块关系图
多模块设计说明
- 父项目 POM: 定义了整个聚合项目的公共配置,如插件、依赖、属性等。它通过
<modules>
标签聚合了所有的子模块。 - 模块 A/B/C/D: 代表项目中的独立模块,每个模块都有自己的 POM 文件,并且可以包含自己的子模块。
- 子模块 A1/A2, B1/B2, C1: 表示模块内部的子模块。这些子模块可以进一步细分实现细节。
优点
- 清晰的项目结构: 每个模块定义了独立的功能,使得项目结构清晰。
- 并行开发: 团队成员可以在不同的模块上同时工作。
- 独立部署: 每个模块可以独立部署,有助于持续集成和持续部署 (CI/CD)。
- 重用性: 公共模块可以在不同的项目中重用。
- 易于维护: 模块化设计使得代码更易于理解和维护。
- 构建性能: 只有更改的模块会被重新构建,提高了构建效率。
2.2 多模块背景
在软件开发中,多模块设计是一种常见的项目结构方式,尤其适用于大型和复杂的项目。使用 Maven 进行多模块项目开发时,可以有效地组织代码、减少重复工作、提高构建效率,并促进项目的模块化和可维护性。以下是多模块设计的一些背景和优点:
目的
- 团队协作: 在团队开发环境中,不同的团队成员或团队可能需要同时在不同的功能模块上工作。
- 代码重用: 通过将共用的代码和资源放入独立的模块中,可以在多个项目或模块间重用这些代码。
- 解耦合: 将应用程序拆分成独立的模块有助于降低模块间的耦合度,提高系统的灵活性。
- 并行开发: 独立的模块可以被不同的团队并行开发和部署。
- 构建性能: 对单独模块进行增量构建,只有更改的模块会被重新构建,节省时间。
优点
- 组织清晰: 将项目分解成模块使得代码库更加结构化和清晰。
- 易于维护: 模块化设计让代码更易于理解和维护。
- 独立部署: 各个模块可以独立部署或更新,而不需要重新部署整个应用程序。
- 并行开发: 开发者可以同时在不同的模块上工作,提高了开发效率。
- 依赖管理: Maven 可以有效地管理模块间的依赖关系。
- 构建灵活性: 可以对整个项目进行构建,也可以只构建单个模块。
- 重用性: 公共模块如日志库或数据库访问库可以被多个项目重用。
- 持续集成: 多模块项目可以更好地与持续集成 (CI) 流程集成。
案例
例如:电子商务平台,它可能包括以下模块:
- web-app: 包含 Web 应用程序代码。
- service: 提供业务逻辑实现。
- data-model: 定义共享的数据模型。
- utilities: 包含通用工具类。
在 Maven 中,你可以在一个父项目中聚合这些模块,并为每个模块创建单独的子项目。
Maven 多模块配置案例
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>ecommerce</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>web-app</module>
<module>service</module>
<module>data-model</module>
<module>utilities</module>
</modules>
</project>
子模块 POM (web-app/pom.xml)
<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>parent-project</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- 如果父模块在不同的集团或版本,需要指定relativePath -->
<!-- <relativePath>../../parent/pom.xml</relativePath> -->
</parent>
<artifactId>web-app</artifactId>
<name>Web Application Module</name>
<!-- 子模块特定的配置和依赖 -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>service-module</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- 其他依赖 -->
</dependencies>
<build>
<!-- 子模块特定的构建配置 -->
</build>
</project>
这种多模块设计使得每个子模块可以独立开发和构建,同时保持了项目整体的一致性和协调性。
3、maven 属性
属性定义/使用/继承关系图
在 Maven 的 pom.xml
文件中,<properties>
元素用来定义一组属性,这些属性可以在 POM 文件的任何地方重复使用,从而提高配置的可维护性和一致性。属性可以是项目特定的,也可以是被继承的父项目中的属性。
3.1 属性的作用
- 提高可维护性:通过集中定义属性,你可以在一个地方更新属性值,而不必在多个地方进行更改。
- 增加可读性:使用明确的属性名称可以提高 POM 文件的可读性。
- 便于配置:属性可以在构建配置中重复使用,如插件配置、依赖版本等。
3.2 XML案例
<properties>
<!-- 定义项目源代码的编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 定义编译器使用的 Java 版本 -->
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
3.3 使用属性
在 POM 文件中,你可以在任何需要的地方使用这些属性,例如在构建配置中:
<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>
在这个例子中,maven-compiler-plugin
使用了在 <properties>
中定义的 maven.compiler.source
和 maven.compiler.target
属性。
3.4 继承和聚合中使用
- 继承:
- 子项目可以继承父项目的属性。
- 子项目通过
parent
标签继承父项目的配置,如依赖、插件和构建设置。
- 聚合:在多模块项目中,父项目可以定义一组公共属性供所有子项目使用。
3.5 总结
通过在 POM 文件中定义属性,你可以创建一个更干净、更易于维护的项目构建配置。这些属性可以在构建生命周期的任何阶段使用,从而确保整个项目的配置一致性。
4、maven 部署
4.1 部署流程
在 Maven 中,<distributionManagement>
部分是用来定义项目产生的构件(artifacts)的部署和分发细节。这包括指向远程仓库的详细信息,构件应该被发布到哪个仓库,以及快照版本和发布版本的处理方式。
详细步骤
- 编译: 将源代码编译成字节码。
- 测试: 运行测试用例,确保代码质量。
- 打包: 将编译后的代码打包成可分发的格式。
- 部署: 根据版本类型将构件部署到对应的仓库。
- 生成项目网站: 生成项目文档和报告。
- 部署到网站服务器: 将生成的网站部署到服务器。
4.2 部署管理(Distribution Management)
- 作用:定义项目的部署和分发细节,允许你指定构件发布到的远程仓库。
XML 配置案例
<distributionManagement>
<!-- 发布版本的仓库配置 -->
<repository>
<id>releases</id> <!-- 仓库的唯一标识符,用于匹配服务器配置 -->
<name>Releases Repository</name> <!-- 仓库的描述性名称 -->
<url>https://repo.example.com/releases</url> <!-- 发布版本的构件部署到的 URL -->
</repository>
<!-- 快照版本的仓库配置 -->
<snapshotRepository>
<id>snapshots</id> <!-- 快照仓库的唯一标识符 -->
<name>Snapshots Repository</name> <!-- 快照仓库的描述性名称 -->
<url>https://repo.example.com/snapshots</url> <!-- 快照版本的构件部署到的 URL -->
</snapshotRepository>
<!-- 项目网站部署配置 -->
<site>
<id>website</id> <!-- 网站的唯一标识符 -->
<name>Website</name> <!-- 网站的描述性名称 -->
<!-- 网站部署的 URL,使用 DAV 协议 -->
<url>https://website.example.com/maven</url>
</site>
<!-- 构件重定位配置 -->
<relocation>
<groupId>com.example</groupId> <!-- 构件所属的组 ID -->
<artifactId>my-project</artifactId> <!-- 构件的项目 ID -->
<version>1.2.3</version> <!-- 构件的版本 -->
<message>Moved to new repo</message> <!-- 重定位的描述信息 -->
</relocation>
</distributionManagement>
XML说明
<repository>
: 用于配置发布版本的构件应该部署到的远程仓库。<id>
: 远程仓库的 ID,这个 ID 需要与<servers>
元素中定义的服务器 ID 匹配,以便 Maven 知道使用哪个服务器配置进行部署。<name>
: 仓库的名称,提供易于理解的描述。<url>
: 仓库的 URL 地址,构件将被部署到这个地址。
<snapshotRepository>
: 用于配置快照版本的构件应该部署到的远程仓库。快照版本通常用于开发过程中,因此可能会更频繁地更新。<site>
: 用于配置项目网站报告应该部署到的位置。这通常是一个 Web 服务器的地址,Maven 可以自动将生成的网站报告部署到这个地址。<relocation>
: 如果项目被移到了一个新的组 ID 或新的仓库,可以使用这个元素来指定新的部署位置。这在项目迁移时非常有用。
注意事项
- 部署管理配置通常用于 CI/CD 流程中,确保构建的构件可以自动部署到指定的远程仓库。
- 确保远程仓库的 URL 正确无误,并且有权限写入。
- 配置的 ID 需要与服务器配置中的 ID 匹配,才能正确部署。
5、maven 构建方式
5.1 构建流程
增量构建 (Incremental Builds) 概念图说明
- 开始构建: 开始 Maven 构建过程。
- 检测变更: Maven 检测自上次构建以来源代码或资源文件是否有变更。
- 有变更: 如果检测到变更,Maven 编译变更的部分。
- 编译变更部分: 仅对变更的源代码进行编译。
- 无变更: 如果没有检测到变更,Maven 跳过编译步骤。
- 跳过编译: Maven 跳过编译步骤,直接进行后续任务。
- 构建成功: 构建过程完成。
并行构建 (Parallel Builds) 概念图说明
- 开始并行构建: 开始 Maven 并行构建过程。
- 任务分配: Maven 将构建任务分配给多个线程。
- 执行任务1/2/3/4: 各个线程执行分配的构建任务。
- 等待其他任务: 一个线程完成任务后,等待其他线程完成。
- 所有任务完成: 所有线程的任务完成后,构建成功。
使用场景
- 增量构建: 适用于需要频繁构建的项目,可以避免重复编译未修改的代码,节省时间。
- 并行构建: 适用于多核处理器系统,可以充分利用 CPU 资源,加快构建速度。
5.2 构建详细说明
Maven 的反应式构建特性主要包括增量构建和并行构建。这些特性使 Maven 能够更智能、更高效地执行构建任务。以下是对这两个特性的详细说明:
增量构建 (Incremental Builds)
增量构建是指 Maven 能够检测到自上次构建以来源代码或资源文件的变更,并仅对发生变更的部分进行重新构建。这可以显著减少构建时间,特别是在大型项目中。
- 原理: Maven 通过比较文件的时间戳和内容来确定哪些文件自上次构建以来发生了变化。
- 好处: 只构建必要的部分,避免不必要的编译和测试,从而节省时间。
- 使用: 通常无需额外配置,Maven 默认启用增量构建。
并行构建 (Parallel Builds)
并行构建是指 Maven 能够同时执行多个构建任务,这可以充分利用多核处理器的优势,加快构建速度。
- 原理: Maven 通过多线程技术并行执行构建任务。
- 好处: 加快构建速度,特别是在多核处理器的系统上。
- 使用: 可以通过 Maven 命令行选项或在
pom.xml
中配置并行构建。
如何配置并行构建
在 Maven 3.5.0 及以上版本,可以通过命令行选项启用并行构建:
mvn clean install -T 4
这里 -T
选项后面跟的数字 4
表示使用 4 个线程来执行构建任务。
在 pom.xml
中,可以这样配置:
<build> <!-- 定义项目的构建细节 -->
<plugins> <!-- 构建过程中使用的插件列表 -->
<plugin> <!-- 单个插件的配置 -->
<groupId>org.apache.maven.plugins</groupId> <!-- 插件的组唯一标识符,通常是插件的开发者或组织 -->
<artifactId>maven-surefire-plugin</artifactId> <!-- 插件的唯一基础名称,表示这是一个用于测试的插件 -->
<version>2.22.2</version> <!-- 插件的版本号,确保使用特定版本的插件 -->
<configuration> <!-- 插件的详细配置,用于指定插件执行时的具体参数 -->
<parallel>classes</parallel> <!-- 指定并行测试的模式,这里使用类级别的并行执行 -->
<threadCount>4</threadCount> <!-- 指定并行执行时使用的线程数,这里设置为 4 个线程 -->
</configuration>
</plugin>
</plugins>
</build>
这里 parallel
标签用于指定并行测试的模式(例如 classes
表示按类进行并行),threadCount
用于指定线程数。