properties
本章承接 parent 继承和聚合,深入讲解 Maven 的属性系统。
properties是 Maven POM 的"变量声明区",它让版本号、路径、编码等配置值从"硬编码"变为"可引用",是实现"一处修改、全局生效"的技术基础。
核心机制
官方明确将 properties 定位为变量系统。它的设计目的是消除重复、集中管理易变配置,让 POM 更具可维护性。
properties 标签的语法
在 POM 的 <properties> 区域,你可以定义任意名称的属性:
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.0</spring-boot.version>
<mysql.version>8.0.33</mysql.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
命名规范:
- 使用点号分隔的层级命名(如
java.version) - 避免与 Maven 内置属性冲突(如
project.version、project.basedir) - 自定义属性建议加前缀(如
feixiang.mysql.version)以避免命名空间污染
${property} 引用语法
定义后的属性可以在 POM 的任何支持表达式的地方用 ${} 引用:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
内置属性与自定义属性
Maven 提供了大量内置属性,无需在 <properties> 中定义即可使用:
| 内置属性 | 含义 | 示例 |
|---|---|---|
${project.version} | 当前 POM 的版本号 | 2.0.0 |
${project.basedir} | 当前 POM 所在目录 | C:\workspace\employee-system |
${project.build.directory} | 构建输出目录 | target |
${env.HOME} | 环境变量 | /home/xiaocui |
${java.home} | JDK 安装目录 | C:\Program Files\Java\jdk-17 |
统一版本管理
properties 最常见的用途是统一依赖版本管理。在父 POM 中定义版本属性,子 POM 通过 ${} 引用,升级时只需修改父 POM 一处。
生活类比:公司通讯录
想象 properties 是公司通讯录:
- 定义属性 = 把员工的手机号存进通讯录。
java.version=17就是"Java 版本这个员工的号码是 17"。 - 引用属性 = 需要联系某人时,查通讯录而不是背号码。
${java.version}就是"帮我查一下 Java 版本员工的号码"。 - 统一修改 = 员工换号了,只需在通讯录改一次。所有之前查过这个号码的人都会自动拿到新号。
如果没有通讯录(properties),每次打电话(写依赖版本)都要背号码(硬编码)。员工换号(版本升级)时,你得把所有记过旧号码的纸条(POM 文件)全部翻出来改一遍。
图示
上图展示了 properties 的核心价值:父 POM 集中定义"变量",子 POM 通过 ${} 引用"变量值"。当父 POM 中的 java.version 从 17 改为 21 时,所有引用它的子 POM 自动生效,无需逐个修改。
完整示例
场景
飞翔科技的 feixiang-parent 管理着 5 个子项目,每个子项目都依赖 Spring Boot 3.2.0 和 MySQL 8.0.33。CTO 大翔要求:升级 Spring Boot 到 3.3.0 时,只改一处配置,所有子项目自动生效。
操作前:硬编码版本
feixiang-parent/pom.xml(错误示范):
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.0</version> <!-- 硬编码 -->
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version> <!-- 硬编码 -->
</dependency>
</dependencies>
</dependencyManagement>
问题:升级 Spring Boot 时,白歌需要检查所有子项目的 pom.xml,确认没有遗漏的硬编码版本。某个子项目如果偷偷写了自己的 <version>3.2.0</version>,升级时就会被遗漏,导致版本不一致。
操作步骤:用 properties 统一管理
第一步:在父 POM 中定义版本属性
<properties>
<java.version>17</java.version>
<spring-boot.version>3.2.0</spring-boot.version>
<mysql.version>8.0.33</mysql.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
第二步:子 POM 引用属性(或继承管理后的无版本依赖)
employee-system/pom.xml:
<project>
<parent>
<groupId>com.feixiang</groupId>
<artifactId>feixiang-parent</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>employee-system</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 版本由父 POM 的 dependencyManagement 管理,底层通过 ${spring-boot.version} 解析 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- source/target 通过 ${java.version} 继承 -->
</plugin>
</plugins>
</build>
</project>
操作结果:版本升级前后对比
升级前(properties 定义):
<properties>
<spring-boot.version>3.2.0</spring-boot.version>
</properties>
所有引用处的实际值:
| 位置 | 生效版本 |
|---|---|
feixiang-parent 的 dependencyManagement | 3.2.0 |
employee-system 的 spring-boot-starter-web | 3.2.0 |
payroll-service 的 spring-boot-starter-web | 3.2.0 |
employee-web 的 spring-boot-starter-web | 3.2.0 |
升级后(只改父 POM 一处):
<properties>
<spring-boot.version>3.3.0</spring-boot.version>
</properties>
所有引用处的实际值:
| 位置 | 生效版本 |
|---|---|
feixiang-parent 的 dependencyManagement | 3.3.0 |
employee-system 的 spring-boot-starter-web | 3.3.0 |
payroll-service 的 spring-boot-starter-web | 3.3.0 |
employee-web 的 spring-boot-starter-web | 3.3.0 |
变化分析:
- 白歌升级 Spring Boot 时,只需修改
feixiang-parent中的<spring-boot.version>一行 - 小崔在
employee-system中无需任何修改,重新构建即自动使用 3.3.0 - 李眉检查构建日志时,看到所有子项目下载的 Spring Boot 依赖版本一致,没有冲突
易错点与常见问题
误区一:properties 定义了,但引用处拼写错误
错误配置:
<properties>
<mysql.version>8.0.33</mysql.version>
</properties>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${myql.version}</version> <!-- 拼写错误!少了 t -->
</dependency>
后果:Maven 解析 ${myql.version} 时找不到定义,直接保留原字符串。构建时会报错:
[ERROR] 'dependencies.dependency.version' for com.mysql:mysql-connector-j:jar must be a valid version but is '${myql.version}'.
纠正:properties 的命名和引用必须完全一致。建议使用 IDE 的自动补全功能,或统一命名规范(如所有版本属性以 .version 结尾)。
误区二:在子 POM 中重复定义同名属性,以为会覆盖父 POM
配置(子 POM 中):
<properties>
<java.version>21</java.version>
</properties>
后果:子 POM 中定义的 java.version 确实会覆盖父 POM 的值,但只在当前子 POM 生效。其他兄弟模块仍然使用父 POM 的值。这种"局部覆盖"会导致同一平台的不同服务使用不同的 Java 版本,增加运维复杂度。
纠正:如果确实需要某个子项目使用不同版本,应在属性名上做区分(如 payroll.java.version),而不是直接覆盖通用属性。平台级属性应在父 POM 统一管理。
误区三:把敏感信息放进 properties
错误配置:
<properties>
<jdbc.password>MySecret123</jdbc.password>
</properties>
后果:密码被硬编码在 pom.xml 中,提交到 Git 后所有团队成员都能看到。更危险的是,如果项目开源或打包发布,密码会随 POM 一起泄露。
纠正:敏感信息(密码、API Key、Token)绝对不应该放在 pom.xml 的 properties 中。应使用环境变量、外部配置文件或 Maven 的 settings.xml 中的 <servers> 配置。
小结
properties 是 Maven POM 的变量系统,通过 <properties> 定义值、通过 ${} 引用值,实现了配置的集中管理和灵活复用。在父 POM 中用 properties 统一管理依赖版本、Java 版本、编码等关键参数,可以让版本升级从"全项目搜索替换"变为"修改一行、全局生效"。注意避免拼写错误、谨慎使用局部覆盖、绝不存放敏感信息。
本章与全局的关系:本章讲解了 POM 内部的变量机制。下一节将讲解 BOM(Bill of Materials),它是 properties + dependencyManagement 的高级组合形式,用于管理更复杂的第三方生态版本。