@ConfigurationProperties才是YYDS,别再迷信@Value了!——盘点SpringBoot获取配置文件内容的几种方式

文章介绍了SpringBoot中获取配置文件内容的两种主要方式:@ConfigurationProperties和@Value。@ConfigurationProperties适用于批量注入和处理复杂数据类型,而@Value则更直接地用于单个属性注入。对于自定义配置文件,可以通过@PropertySource加载,但默认只支持properties格式。若要加载YML格式,需自定义工厂类如YmlConfigFactory。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

那是一个风平浪静的周二,版本迭代顺利上线。然而,宁静在凌晨三点被刺耳的电话告警撕碎——核心文件处理服务宕机,P0级故障!

所有相关人员,包括我,被从床上薅了起来。情况紧急,新上线的版本是最大嫌疑。我们焦头烂额地排查日志,发现满屏的 NullPointerException,源头指向一个新功能的文件路径处理逻辑。更致命的是,异常日志在几小时内撑爆了磁盘,导致整台服务器雪崩!

查来查去,最终定位到的“犯罪现场”让所有人都傻眼了。

通往地狱的代码

出问题的代码,表面看平平无奇,其实每个配置项都像一座孤岛,很多新手甚至老手都这么写:

@Service
public class UnstableFileProcessor {

    @Value("${file.windows.path}")
    private String windowsPath;

    @Value("${file.linux.path}")
    private String linuxPath;

    @Value("${file.buffer-size}")
    private int bufferSize;

    @Value("${file.max-retry}")
    private int maxRetry;

    public void processFile() {
        String path = isWindows() ? windowsPath : linuxPath;
        File file = new File(path); // 如果path为null,这里就准备抛出NPE
        // ...
    }
}

问题出在哪?运维在更新生产环境的 application.yml 时,手抖漏掉了新增的 file.linux.path 配置。而 @Value 在找不到对应配置时,不会在启动时报错,它会默默地将 null 注入给 linuxPath 变量。

于是,应用在Linux服务器上看似正常启动,一旦流量进来调用到 processFile() 方法,NullPointerException 就像一颗定时炸弹,瞬间引爆。

SpringBoot提供的高内聚的优雅写法

在定位到问题后,我花了10分钟,把这段“地雷代码”重构成下面这样。

/**
 * 文件处理相关配置
 * 使用@ConfigurationProperties,所有相关配置一目了然
 */
@Component
@ConfigurationProperties(prefix = "file")
public class FileProperties {
    private String windowsPath;
    private String linuxPath;
    private int bufferSize = 4096; // 可以设置默认值
    private int maxRetry = 3;
}

然后,在业务代码中使用:

@Service
public class StableFileProcessor {

  	@Autowired
    private FileProperties fileProperties;

    public void processFile() {
        // fileProperties.getLinuxPath() 调用,清晰、安全
        String path = isWindows() ? fileProperties.getWindowsPath() : fileProperties.getLinuxPath();
        File file = new File(path);
        // ...
    }
}

为什么@Value是魔鬼?

  1. 松散 vs. 内聚@Value 将配置项打得七零八落,散布在代码的各个角落。而 @ConfigurationProperties 将一组关联配置封装在一个类中,形成一个有业务含义的整体,高内聚,易于管理和维护。
  2. 编译时安全 vs. 运行时炸弹:使用 @ConfigurationProperties,当你想重构,比如修改配置前缀 file 时,IDE的重构功能可以帮你搞定一切。但如果你用的是 @Value("${file.linux.path}"),想把 file 改成 storage,你只能全局搜索字符串,祈祷自己不要遗漏。
  3. 弱类型 vs. 强类型@ConfigurationProperties 支持复杂的类型绑定,如 ListMap 甚至嵌套对象。@Value 只能处理简单的值。
  4. 强大的校验@ConfigurationProperties 支持JSR303数据校验,你可以在字段上加 @NotNull, @Min(1) 等注解,如果配置文件不合法,应用启动会直接失败!这就能在上线前发现问题,而不是等到凌晨三点。

扩展:自定义配置文件的终极玩法

有人会说:“我的配置不在 application.yml 里,而是在一个独立的 custom.properties 里,@ConfigurationProperties 还好使吗?”

Spring Boot在启动的时候会自动加载 application.xxx 和 bootsrap.xxx ,但是为了区分,有时候需要自定义一个配置文件,那么如何从自定义的配置文件中取值呢?

只需要在启动类上标注 @PropertySource 并指定你自定义的配置文件即可完成。

@SpringBootApplication
@PropertySource(value = {"classpath:custom.properties"})
public class DemoApplication{ }

那么custom.yml也可以吗?

问得好。@PropertySource 默认只认 .properties 文件,想让它加载 .yml?别慌,祭出我们的“终极武器”——自定义 PropertySourceFactory

加载自定义yml文件

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;

import java.io.IOException;
import java.util.Properties;

public class YmlConfigFactory extends DefaultPropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = name != null ? name : resource.getResource().getFilename();
        if (sourceName != null && (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml"))) {
            Properties propertiesFromYml = loadYml(resource);
            return new PropertiesPropertySource(sourceName, propertiesFromYml);
        }
        return super.createPropertySource(name, resource);
    }

    private Properties loadYml(EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
}

第二步,修改启动类:

@SpringBootApplication
@PropertySource(value = {"classpath:custom.yml"}, factory = YmlConfigFactory.class)
public class DemoApplication {
    // ...
}

只需要这两步,你的 @ConfigurationProperties 就能精准地从任何自定义的 yml 文件中加载配置,稳如泰山。

写在文末

  • 用@Value写业务,就是给午夜的自己埋雷。
  • 关联配置超三个,无脑@ConfigurationProperties准没错!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CV大魔王

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

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

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

打赏作者

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

抵扣说明:

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

余额充值