1. 概述
在日常开发中,项目的构建配置(如 Maven 的 pom.xml
或 Gradle 的 build.gradle
)通常包含大量元信息:版本号、项目名称、描述、构建时间等。这些信息不仅对构建系统有用,在应用运行时也常常需要暴露给外部,比如在监控接口、健康检查页或管理后台展示当前版本。
与其把这些信息硬编码到代码或配置文件中,不如直接从构建配置中提取。这样既能保证一致性,又能避免重复维护。
本文将介绍如何在 Spring Boot 项目中,优雅地将构建信息注入到应用内部并加以使用,涵盖 Maven 和 Gradle 两种构建工具的实践方式。
2. 构建信息示例
假设我们想在首页展示应用的名称和版本信息。这些内容通常已经定义在 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>
<artifactId>spring-boot</artifactId>
<name>spring-boot</name>
<packaging>war</packaging>
<description>This is simple boot application for Spring boot actuator test</description>
<version>0.0.1-SNAPSHOT</version>
...
</project>
我们的目标是让 Spring Boot 应用能直接读取 project.description
和 project.version
这类字段。
3. 在 application.properties 中引用构建属性
最简单的方式是在 application.properties
中通过占位符引用 Maven 属性:
application-description=@project.description@
application-version=@project.version@
✅ 关键点:使用 @xxx@
包裹属性名,Spring Boot 会在打包时自动替换为 pom.xml
中的实际值。
这个过程叫做 资源过滤(Resource Filtering),由 Maven 的 maven-resources-plugin
完成。
⚠️ 注意事项:
- ❌ 该机制仅对
src/main/resources
生效,src/test/resources
不会触发过滤。 - ❌ 如果你使用
spring-boot:run
并设置了addResources=true
,会直接加载源目录资源,绕过过滤机制,导致占位符未被替换。 - ✅ 此功能开箱即用的前提是:**继承了
spring-boot-starter-parent
**。
3.1 不使用 spring-boot-starter-parent 时的配置
如果你的项目没有继承 spring-boot-starter-parent
(比如多模块聚合项目),需要手动启用资源过滤。
1. 启用 filtering
在 pom.xml
中显式开启资源过滤:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
2. 配置 maven-resources-plugin 分隔符
为了避免与 Spring 的 ${}
占位符冲突,建议自定义分隔符并关闭默认行为:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
✅ useDefaultDelimiters=false
可防止 ${}
被 Maven 提前解析,保留给 Spring 容器处理。
4. 在 YAML 文件中使用构建属性
YAML 对 @
字符敏感(它是 YAML 的锚点语法),直接使用 @xxx@
会导致解析失败。
解决方法有两种:
方案一:更换 Maven 的占位符分隔符
将 @
改为其他符号,比如 ^
:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimiter>^</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
然后在 application.yml
中使用:
application-description: ^project.description^
application-version: ^project.version^
方案二:通过 properties 全局覆盖
更简洁的方式是在 pom.xml
中设置:
<properties>
<resource.delimiter>^</resource.delimiter>
</properties>
效果相同,但配置更集中。
5. 使用 BuildProperties Bean 获取构建信息
上面的方法适合静态配置注入,但如果想在 Java 代码中动态获取构建信息(如版本、构建时间等),推荐使用 Spring Boot 内置的 BuildProperties
类。
5.1 Maven 配置
在 pom.xml
中为 spring-boot-maven-plugin
添加 build-info
目标:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
<configuration>
<additionalProperties>
<java.version>${java.version}</java.version>
<description>${project.description}</description>
<custom.value>123</custom.value>
</additionalProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
构建后,会在 target/classes/META-INF/build-info.properties
生成如下内容:
build.artifact=spring-boot-properties
build.custom.value=123
build.description=Spring Boot Properties Module
build.group=com.baeldung.spring-boot-modules
build.java.version=11
build.name=spring-boot-properties
build.time=2023-04-08T04:29:28.905Z
build.version=0.0.1-SNAPSHOT
✅ 自动生成 build.time
,非常实用。
5.2 在代码中访问 BuildProperties
Spring Boot 会自动将 build-info.properties
加载为 BuildProperties
Bean。
直接注入即可使用:
@Autowired
private BuildProperties buildProperties;
示例:单元测试验证
@Test
void givenBuildPropertiesBean_WhenFetchDefaultBuildProperties_ThenGetValidValues() {
Assertions.assertEquals("spring-boot-properties", buildProperties.getArtifact());
Assertions.assertEquals("com.baeldung.spring-boot-modules", buildProperties.getGroup());
Assertions.assertEquals("0.0.1-SNAPSHOT", buildProperties.getVersion());
}
获取自定义属性:
@Test
void givenBuildPropertiesBean_WhenFetchCustomBuildProprties_ThenGetValidValues() {
Assertions.assertEquals("123", buildProperties.get("custom.value"));
Assertions.assertNotNull(buildProperties.get("java.version"));
Assertions.assertEquals("Spring Boot Properties Module", buildProperties.get("description"));
}
⚠️ 注意:自定义字段通过 get("key")
访问,返回 String
类型。
5.3 Gradle 配置
Gradle 用户只需在 build.gradle
中添加:
springBoot {
buildInfo {
properties {
additional = [
'description': project.getDescription(),
'java.version': JavaVersion.current(),
'custom.value': 123,
]
}
}
}
构建后,文件会生成在:
build/resources/main/META-INF/build-info.properties
内容与 Maven 版本一致。✅ 应用代码无需任何改动,Spring Boot 自动识别并加载。
6. 总结
方法 | 适用场景 | 推荐度 |
---|---|---|
@xxx@ + resource filtering |
快速注入配置文件 | ⭐⭐⭐⭐ |
更换 delimiter(如 ^xxx^ ) |
使用 YAML 时必备 | ⭐⭐⭐⭐ |
BuildProperties Bean |
代码中动态读取构建信息 | ⭐⭐⭐⭐⭐ |
✅ 最佳实践建议:
- 日常项目优先使用
spring-boot-starter-parent
,省去大量配置。 - 展示类信息(如版本页)使用
BuildProperties
,灵活且类型安全。 - 构建时间、JVM 版本等运维信息,通过
additionalProperties
注入,便于问题排查。 - 避免在测试资源中依赖构建属性,容易踩坑。
通过合理利用 Spring Boot 的构建集成能力,可以轻松实现“一次定义,处处可用”,彻底告别硬编码。