1788 字
9 分钟
Maven 以及 pom
Maven 是一个项目管理和构建的自动化工具,主要服务于 JAVA 项目。其特性在于
- 标准化项目管理 (统一的项目目录结构)
- 依赖管理 (自动管理第三方库及其版本、传递性依赖)
- 构建生命周期 (标准的构建流程-编译、测试、打包、部署)
- 插件机制 (通过插件扩展功能)
pom.xml 详解
POM (Project Object Model) 是 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- POM 版本,通常固定为 4.0.0 --> <modelVersion>4.0.0</modelVersion>
<!-- 项目坐标:唯一标识一个项目 --> <groupId>com.example</groupId> <!-- 组织/公司标识 --> <artifactId>my-app</artifactId> <!-- 项目名称 --> <version>1.0.0-SNAPSHOT</version> <!-- 项目版本 --> <packaging>jar</packaging> <!-- 打包方式:jar/war/pom等 -->
</project>坐标详解
| 元素 | 说明 | 示例 |
|---|---|---|
| groupId | 组织标识,通常为域名倒写 | com.example, cc.ieaf |
| artifactId | 项目唯一标识 | my-app, springsecurity-demo |
| version | 项目版本号 | 1.0.0, 2.0.0-beta |
| packaging | 打包方式 (可选) | jar, war, pom, maven-plugin |
| classifier | 分类器 (可选) | sources, javadoc |
版本号规范
Maven 版本号规范允许使用数字、点、连字符、下划线、字母的组合。
<version>2.5.6.RELEASE</version> <!-- Spring 传统格式 --><version>2.5.6</version> <!-- 纯数字格式 --><version>2.5.6-Final</version> <!-- 带标识符 --><version>2.5.6.20201231.123456</version> <!-- 时间戳版本 -->版本号排序规则(从小到大):
2.5.6-SNAPSHOT(开发版)2.5.6-alpha(内测版)2.5.6-beta(公测版)2.5.6-milestone(里程碑版)2.5.6.RELEASE或2.5.6(正式版)2.5.6.RELEASE.1(补丁版)
依赖管理
<dependencies> <!-- 一个依赖项 --> <dependency> <!-- 组织标识 --> <groupId>org.springframework.boot</groupId> <!-- 项目唯一标识 --> <artifactId>spring-boot-starter-web</artifactId> <!-- 项目版本号 --> <version>2.7.0</version> <!-- 依赖范围 --> <scope>compile</scope> <!-- 是否可选 --> <optional>false</optional> <!-- 排除传递性依赖 --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency></dependencies>依赖范围 (scope)
| 范围 | 说明 |
|---|---|
| compile | 默认值,所有阶段都有效 |
| provided | 编译时有效,运行时由 JDK 或容器提供 |
| runtime | 编译时不需要,运行时需要 |
| test | 测试时需要 |
| system | 类似 provided 需要显式指定路径 |
| import | 仅用于 dependencyManagement, 导入依赖 |
是否可选 (optional)
这个选项表示这个依赖是否应该被传递继承
optional=true: 表示当前项目需要这个依赖,但是不强制要求引用我这个项目的使用者也被传递需要这个依赖optional=false: (默认值)表示当前项目需要这个依赖,同时引用我这个项目的使用者也会自动获得这个依赖 举个例子:我写一个项目的时候用到了lombok, 但是它仅在我编译代码的时候需要,如果别人要使用我写的包不一定就需要它,这种时候就可以使用optional=true
属性配置
<properties> <!-- 项目编码 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Java 版本 --> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target>
<!-- 自定义属性:统一版本管理 --> <spring.version>5.3.20</spring.version> <junit.version>5.8.2</junit.version></properties>
<!-- 使用属性 --><dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency></dependencies>配置属性中,一些是内置属性,直接配置使用。一些是自定义配置,需要自己在用到的地方通过 ${spring.version} 这样的形式进行引用。
常见的内置属性
| 属性名 | 说明 | 示例值 |
|---|---|---|
project.build.sourceEncoding | 源码编码 | UTF-8 |
project.reporting.outputEncoding | 报告编码 | UTF-8 |
maven.compiler.source | Java 源码版本 | 1.8,11,17,21 |
maven.compiler.target | Java 目标版本 | 1.8,11,17,21 |
maven.test.skip | 是否跳过测试 | true/false |
maven.javadoc.skip | 是否跳过javadoc | true/false |
构建配置
<build> <!-- 最终打包的文件名--> <!-- 不写的话,默认就是这个命名 --> <finalName>${project.artifactId}-${project.version}</finalName>
<!-- 资源配置文文件 --> <!-- 不写的话,资源文件路径默认是下面这个 --> <!-- filtering 默认是 false --> <!-- 但是包含的文件默认是所有,下面限定了.yaml和.xml后缀的 --> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <includes> <include>**/*.yaml</include> <include>**/*.xml</include> </includes> </resource> </resources>
<!-- 插件配置 --> <plugins> <plugin> <!-- 和上述依赖类似 --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.10.1</version> <!-- 插件的具体配置,要根据插件决定 --> <configuration> <source>11</source> <target>11</target> </configuration> </plugin>
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <!-- 和依赖类似,可以排除传递包 --> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins></build>filtering=true 的作用: 允许在构建时替换资源文件中的占位符,例如
app: name: ${project.name} version: ${project.version} env: ${env} url: ${db.url}-
用来替换这些占位符的可以来自
pom.xml:<properties><!-- 可以是内置属性 --><project.version>1.0.0</project.version><!-- 也可以是自定义属性 --><env>dev</env></properties><build><ressources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource></ressources></build> -
也可以用命令行,通过
-D参数传递Terminal window mvn package -ddb.url=jdbc:mysql://localhost:3306/test -
还可以是来自系统变量 例如系统变量里有
$OPENAI_API=sk...,在资源文件里也能使用src/main/resources/application.yaml openai_api: ${OPENAI_API}
仓库配置
<!-- 定义项目特有的仓库 --><repositories> <repository> <id>aliyun</id> <name>阿里云仓库</name> <url>https://maven.aliyun.com/repository/public</url> <!-- 允许使用正式发行版本 --> <releases> <enabled>true</enabled> </releases> <!-- 禁止使用开发快照版本 --> <snapshots> <enabled>false</enabled> </snapshots> </repository></repositories>
<!-- 插件仓库 --><pluginRepositories> <pluginRepository> <id>aliyun-plugin</id> <url>https://maven.aliyun.com/repository/public</url> </pluginRepository></pluginRepositories>用于自定义项目的依赖仓库和插件仓库,一般不使用,通常是在 Maven 的 settings.xml 文件里配置。
多模块项目
大多数时候一些大型项目会分成多个模块构建,减小项目的耦合性,增大开发效率和灵活性。其实就是把项目里的文件分散到几个独立的模块里去:
spring-boot-multi-module/├── pom.xml (父)├── common/│ ├── pom.xml│ └── src/main/java/com/example/common/...├── service/│ ├── pom.xml│ └── src/main/java/com/example/service/...└── web/ ├── pom.xml └── src/main/java/com/example/web/Application.java父POM (聚合模块)
<!-- 父模块定义 --><groupId>com.example</groupId><artifactId>parent-project</artifactId><version>1.0.0</version><packaging>pom</packaging>
<!-- 定义子模块 --><module>common</module><module>core</module><module>web</module>
<!-- 子模块公用配置 --><properties> <java.version>11</java.version></properties>子 POM
<parent> <groupId>com.example</groupId> <artifactId>parent-project</artifactId> <version>1.0.0</version> <relativePath>../pom.xml</relativePath></parent>
<artifactId>common</artifactId><packaging>jar</packaging>- Maven 是基于坐标识别项目,所以显式地声明父模块的 groupId、artifactId、version 是必须的。
- 子模块通过
<parent>声明继承了父模块的 groupId、artifactId、version 等。 relativePath只是一个辅助提示,如果没找到 Maven 会转而去依赖仓库中去寻找
多模块依赖管理
<!-- 通常用在父POM中 --><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>
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency> </dependencies></dependencyManagement>在 dependencyManagement 中的是声明的依赖版本,可以让子模块引用时无需声明版本,而在子模块里的 dependencies 一般则是直接引入的依赖。
常用插件
| 插件 | 用途 | 常用命令 |
|---|---|---|
maven-compiler-plugin | 编译Java代码 | compile, testCompile |
maven-surefire-plugin | 运行单元测试 | test |
maven-jar-plugin | 打包成JAR | package |
maven-war-plugin | 打包成WAR | package |
maven-source-plugin | 生成源码包 | source |
maven-javadoc-plugin | 生成JavaDoc | javadoc |
spring-boot-maven-plugin | SpringBoot打包 | spring-boot |
Maven 的生命周期
Maven 有三个内置的生命周期:
- default (核心生命周期)
validate -> compile -> test -> package -> verify -> install -> deploy| 阶段 | 说明 |
|---|---|
| validate | 验证项目是否正确 |
| compile | 编译源代码 |
| test | 运行单元测试 |
| package | 打包成 jar/war |
| verify | 检查包是否有效 |
| install | 安装到本地仓库 |
| deploy | 部署到远程仓库 |
- clean (清理)
pre-clean -> clean -> post-clean| 阶段 | 说明 |
|---|---|
| pre-clean | 执行清理前需要完成的工作(例如清除之前的日志) |
| clean | 删除上一次构建生成的所有文件(核心阶段,默认删除 target 目录) |
| post-clean | 执行清理之后的工作(例如清理完成后的通知) |
-
site (生成站点)
Ps. 现在前后端分离基本不会用这个吧
pre-site -> site -> post-site -> site-deploy常用命令
# 清理mvn clean
# 编译mvn compile
# 运行测试mvn test
# 打包mvn package
# 安装到本地仓库mvn install
# 部署到远程仓库mvn deploy
# 跳过测试mvn package -DskipTests
# 指定settings文件mvn clean install -s /path/to/settings.xml
# 查看依赖树mvn dependency:tree
# 查看项目信息mvn help:effective-pom