Skip to content

Spring Boot Gradle Plugin 与 Actuator 集成:构建信息生成详解 🏗️

概述

在现代微服务架构中,了解应用的构建信息对于运维、监控和问题排查至关重要。Spring Boot Actuator 提供了强大的监控和管理功能,而构建信息的自动生成则是其中一个非常实用的特性。

NOTE

Spring Boot Actuator 的 info 端点可以自动发布应用的构建信息,前提是存在 META-INF/build-info.properties 文件。

为什么需要构建信息?🤔

解决的核心痛点

在没有构建信息的情况下,我们经常会遇到以下问题:

  • 版本混乱:不知道当前运行的是哪个版本的应用
  • 问题排查困难:无法快速确定问题出现在哪个构建版本
  • 部署验证复杂:难以验证部署的应用是否为预期版本
  • 监控信息缺失:监控系统无法获取应用的基本构建信息

构建信息的价值

基础配置与使用 🚀

1. 启用构建信息生成

最简单的配置方式是通过 Gradle Plugin 的 DSL:

kotlin
springBoot {
    buildInfo() 
}
groovy
springBoot {
    buildInfo() 
}

TIP

这个配置会自动创建一个名为 bootBuildInfo 的任务,并让 classes 任务依赖于它。

2. 生成的文件位置

构建信息文件会被生成在:

  • 路径build/resources/main/META-INF/build-info.properties
  • 格式:标准的 Properties 文件

默认构建信息详解 📊

Spring Boot 会自动从项目中提取以下信息:

属性默认值来源示例
build.artifactbootJarbootWar 任务的基础名称my-app
build.group项目的 groupcom.example
build.name项目名称My Application
build.version项目版本1.0.0
build.time构建时间2024-01-15T10:30:00Z

实际生成的文件示例

properties
# build-info.properties
build.artifact=my-spring-app
build.group=com.example
build.name=My Spring Application
build.version=1.0.0-SNAPSHOT
build.time=2024-01-15T10\:30\:00.123Z

自定义构建信息 ⚙️

1. 覆盖默认属性

kotlin
springBoot {
    buildInfo {
        properties {
            artifact.set("custom-app-name") 
            version.set("2.1.0") 
            group.set("com.mycompany") 
            name.set("My Custom Application") 
        }
    }
}

2. 排除特定属性

有时我们不希望包含某些默认属性,特别是 time 属性:

kotlin
springBoot {
    buildInfo {
        excludes.set(setOf("time")) 
    }
}

WARNING

build.time 属性会导致每次构建都生成不同的文件,这会影响构建缓存的效率和构建的可重复性。

3. 添加自定义属性

kotlin
springBoot {
    buildInfo {
        properties {
            additional.set(mapOf( 
                "branch" to "main", 
                "commit" to "abc123def", 
                "environment" to "production"
            )) 
        }
    }
}

实际应用场景 💼

场景1:Spring Boot 应用中获取构建信息

kotlin
@RestController
class InfoController {
    
    @Autowired
    private lateinit var buildProperties: BuildProperties
    
    @GetMapping("/version")
    fun getVersion(): Map<String, String> {
        return mapOf(
            "name" to buildProperties.name, 
            "version" to buildProperties.version, 
            "group" to buildProperties.group, 
            "artifact" to buildProperties.artifact, 
            "time" to buildProperties.time.toString() 
        )
    }
}

场景2:健康检查端点集成

kotlin
@Component
class CustomInfoContributor : InfoContributor {
    
    @Autowired
    private lateinit var buildProperties: BuildProperties
    
    override fun contribute(builder: Info.Builder) {
        builder.withDetail("build", mapOf( 
            "version" to buildProperties.version,
            "name" to buildProperties.name,
            "buildTime" to buildProperties.time
        ))
        
        // 添加运行时信息
        builder.withDetail("runtime", mapOf( 
            "uptime" to ManagementFactory.getRuntimeMXBean().uptime,
            "processors" to Runtime.getRuntime().availableProcessors()
        ))
    }
}

场景3:完整的构建配置示例

完整的 build.gradle.kts 配置示例
kotlin
plugins {
    kotlin("jvm") version "1.9.20"
    kotlin("plugin.spring") version "1.9.20"
    id("org.springframework.boot") version "3.2.0"
    id("io.spring.dependency-management") version "1.1.4"
}

group = "com.example"
version = "1.0.0-SNAPSHOT"

// Git 信息获取函数
fun getGitCommitHash(): String {
    return try {
        val process = ProcessBuilder("git", "rev-parse", "--short", "HEAD")
            .directory(rootDir)
            .start()
        process.inputStream.bufferedReader().readText().trim()
    } catch (e: Exception) {
        "unknown"
    }
}

fun getGitBranch(): String {
    return try {
        val process = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
            .directory(rootDir)
            .start()
        process.inputStream.bufferedReader().readText().trim()
    } catch (e: Exception) {
        "unknown"
    }
}

springBoot {
    buildInfo {
        properties {
            // 自定义基本信息
            name.set("My Awesome Spring Boot App")
            artifact.set("awesome-app")
            
            // 添加 Git 信息
            additional.set(mapOf(
                "git.branch" to getGitBranch(),
                "git.commit" to getGitCommitHash(),
                "build.user" to System.getProperty("user.name"),
                "build.java.version" to System.getProperty("java.version"),
                "profile" to (project.findProperty("spring.profiles.active") ?: "default")
            ))
        }
        
        // 排除构建时间以提高构建性能
        excludes.set(setOf("time"))
    }
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-actuator") 
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
}

性能考虑与最佳实践 ⚡

1. 构建时间属性的影响

2. 最佳实践建议

IMPORTANT

性能优化建议

  • 在开发环境中排除 time 属性以提高构建速度
  • 在生产环境中保留 time 属性以便问题追踪
  • 使用 Provider 进行懒加载计算
kotlin
springBoot {
    buildInfo {
        properties {
            // 使用 Provider 进行懒加载
            additional.set(provider { 
                mapOf(
                    "git.commit" to getGitCommitHash(),
                    "build.timestamp" to System.currentTimeMillis().toString()
                )
            })
        }
        
        // 根据环境决定是否排除时间
        if (project.hasProperty("dev")) { 
            excludes.set(setOf("time")) 
        } 
    }
}

监控集成示例 📈

Actuator 端点访问

启用构建信息后,可以通过以下端点访问:

bash
# 获取完整信息
curl http://localhost:8080/actuator/info

# 响应示例
{
  "build": {
    "artifact": "my-app",
    "name": "My Application",
    "time": "2024-01-15T10:30:00.123Z",
    "version": "1.0.0",
    "group": "com.example"
  }
}

与监控系统集成

kotlin
@Component
class MetricsCollector {
    
    @Autowired
    private lateinit var buildProperties: BuildProperties
    
    @Autowired
    private lateinit var meterRegistry: MeterRegistry
    
    @PostConstruct
    fun registerMetrics() {
        // 注册构建信息为标签
        Tags.of(
            "version", buildProperties.version, 
            "artifact", buildProperties.artifact 
        ).let { tags ->
            meterRegistry.gauge("app.info", tags, 1.0) 
        }
    }
}

总结 📝

Spring Boot Gradle Plugin 的构建信息生成功能为我们提供了:

自动化的构建信息收集
标准化的信息格式
灵活的自定义选项
与 Actuator 的无缝集成

通过合理配置构建信息,我们可以显著提升应用的可观测性和运维效率。记住在性能和信息完整性之间找到平衡点,特别是对于 build.time 属性的处理。

TIP

在 CI/CD 流水线中,构建信息可以帮助快速定位问题版本,建议结合 Git 信息和环境标识来构建完整的应用画像。