还在用 @Value 一行行注入配置? @ConfigurationProperties 才是现代Java仔的标配!

最近,我瞅见我们团队一个新人提交了个 PR (代码合并请求)。他用 @Value 注解把 application.properties 里的参数注入到一个重试服务(retry service)里,就像下面这样:
(此处通常会有一个使用 @Value 的代码示例,但原文未提供)

是的,这么写确实能跑起来,而且代码写起来也简单。但作为一个经验丰富的开发者,我脑子里第一个念头就是——“这玩意儿以后扩展起来要命啊。”

这种方式(大量使用 @Value)的问题在于:

  • • 配置分散 (Scattered configuration) — 属性散落在各个类中,难以集中管理、分组或重构。

  • • 缺乏校验 (No validation) — @Value 本身不提供便捷的校验机制,无效的配置值可能会悄无声息地让逻辑在运行时出错。

  • • 缺乏不可变性 (Lack of immutability) — 如果注入的字段不是 final 的,它们理论上可以在运行时被修改(尽管这通常不是好实践)。

  • • 手动设置默认值 (Manual defaulting) — 像 @Value("${retry.attempts:3}") 这样的默认值写法,虽然方便,但当这样的用法变多时,会开始污染业务逻辑代码的可读性。

所以,我建议他改用 @ConfigurationProperties

@ConfigurationProperties 注解能把咱们的 application.properties 或 application.yaml 文件里的外部属性,以类型安全的方式绑定到我们应用程序中的特定 Java 类上。
Spring Boot 的 @ConfigurationProperties 允许我们将一组相关的配置属性映射到一个单独的类中。
从 Spring Boot 3 开始,它还完美支持 Java Records,这给我们带来了不可变性 (immutability) 和更强的类型安全 (type-safety)

使用 @ConfigurationProperties (尤其是配合 Records) 的好处包括:

  • • 🔐 使用 Java Records 实现不可变的配置对象

  • • 🧠 类型安全且对 IDE 友好(编辑器能提供更好的自动补全支持)。

  • • 🧪 支持 JSR-303 校验 (例如 @NotNull@Min 等注解可以直接用在配置属性类上)。

  • • 🧼 关注点分离 (Separation of concerns) — 配置逻辑与业务逻辑清晰分开。

  • • ✅ 测试更简单 — 在单元测试中可以轻松注入 Mock 的配置 Bean。


🛠️ 如何在 Java Records 中使用 @ConfigurationProperties

下面是一个如何操作的例子:

  1. 1. 创建一个配置属性类 (Config Properties Class - 使用 Record)我们先创建一个 record 类来承载相关的配置属性:
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import jakarta.validation.constraints.Max;
    import jakarta.validation.constraints.Min;
    import jakarta.validation.constraints.NotBlank;
    
    // @ConstructorBinding // Spring Boot 3.0 之后,对于 record 和构造器绑定的类,此注解不再是必须的
    @ConfigurationProperties(prefix = "app.retry")// 指定配置文件中的前缀
    publicrecordRetryProperties(
        @Min(1)int maxAttempts,       // 最小尝试次数为1
        @Min(100)long initialIntervalMs, // 初始间隔至少100毫秒
        @Max(5)double multiplier         // 退避乘数最大为5
        // 可以根据需要添加更多属性
    ) {
        // 对于 record,构造器、getter、equals、hashCode、toString 都是自动生成的
        // 可以在这里添加默认构造器或者静态工厂方法(如果需要更复杂的默认逻辑)
        public RetryProperties {
            // 可以在紧凑构造函数中进行额外的校验或规范化(如果JSR-303不够用)
        }
    }
  2. 2. 在主应用类中启用配置属性类的扫描你需要在你的 Spring Boot 主启动类或任何一个 @Configuration 类上,让 Spring Boot 知道去哪里扫描并激活你的 @ConfigurationProperties 类。通常可以通过 @EnableConfigurationProperties 或确保该类能被组件扫描到。示例如下:
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    
    @SpringBootApplication
    @EnableConfigurationProperties(RetryProperties.class)// 明确启用这个配置属性类
    publicclassMyApplication {
        publicstaticvoidmain(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    }
    (或者,如果 RetryProperties 本身被标记为 @Component,并且在组件扫描路径下,有时也能工作,但 @EnableConfigurationProperties 是更推荐的方式)
  3. 3. 在服务类中使用构造器注入来注入配置类现在,你可以在你的服务类(比如 RetryService)中,通过构造器注入这个 RetryProperties 对象了。示例如下:
    import org.springframework.stereotype.Service;
    
    @Service
    publicclassMyRetryService {
    
        privatefinal RetryProperties retryConfig; // 使用 final 保证不可变
    
        // 通过构造器注入 RetryProperties
        publicMyRetryService(RetryProperties retryConfig) {
            this.retryConfig = retryConfig;
        }
    
        publicvoidattemptOperation() {
            intattempts= retryConfig.maxAttempts(); // 从配置对象获取参数
            longinterval= retryConfig.initialIntervalMs();
            doublemultiplier= retryConfig.multiplier();
    
            System.out.println("重试配置 - 最大尝试次数: " + attempts);
            System.out.println("重试配置 - 初始间隔: " + interval + "ms");
            System.out.println("重试配置 - 退避乘数: " + multiplier);
    
            // ... 执行重试逻辑 ...
        }
    }
    当 RetryProperties 作为一个 final 属性通过构造器注入时,其不可变性得到了保证。如果你的服务类使用了像 Lombok 这样的库,并且有 @RequiredArgsConstructor 或 @AllArgsConstructor 注解,Lombok 会自动为你生成包含此参数的构造函数。然后,你就可以从这个配置实例 (retryConfig) 中轻松获取所需的参数了。

虽然 @Value 可能适用于小规模应用或快速原型开发,但一旦遇到以下情况,它很快就会变得难以维护:

  • • 你需要对配置值进行校验

  • • 你使用了多个相互关联的配置值。

  • • 你希望代码整洁、服务可测试

通过使用 @ConfigurationProperties 配合 Java Records,你就采用了现代化的 Spring Boot 开发方式,它能带来整洁的代码、类型安全以及更好的关注点分离

我在应用程序开发中遵循以下规则:

  • • 对于结构化的、可复用的、分组的配置,我使用 @ConfigurationProperties

  • • 而对于快速的、简单的或一次性的单个属性,我才考虑使用 @Value

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java干货

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值