SpringBoot 如何优雅读取配置文件?10分钟教你搞定

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 如何优雅读取配置文件?10分钟教你搞定相关的知识,希望对你有一定的参考价值。

参考技术A 很多时候我们需要将一些常用的配置信息比如阿里云 oss 配置、发送短信的相关信息配置等等放到配置文件中。

下面我们来看一下 Spring 为我们提供了哪些方式帮助我们从配置文件中读取这些配置信息。

application.yml 内容如下:

wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油!my-profile:name: Guide哥email: koushuangbwcx@163.comlibrary:location: 湖北武汉加油中国加油books:    -name: 天才基本法description: 二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息——对方考取的学校,恰是父亲当年为她放弃的那所。    -name: 时间的秩序description: 为什么我们记得过去,而非未来?时间“流逝”意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛·罗韦利用诗意的文字,邀请我们思考这一亘古难题——时间的本质。    -name: 了不起的我description: 如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系? 如何走出人生的艰难时刻?

1.通过 @value 读取比较简单的配置信息

使用 @Value("$property") 读取比较简单的配置信息:

@Value("$wuhan2020")String wuhan2020;

需要注意的是 @value这种方式是不被推荐的,Spring 比较建议的是下面几种读取配置信息的方式。

2.通过@ConfigurationProperties读取并与 bean 绑定

LibraryProperties 类上加了 @Component 注解,我们可以像使用普通 bean 一样将其注入到类中使用。

importlombok.Getter;importlombok.Setter;importlombok.ToString;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.context.annotation.Configuration;importorg.springframework.stereotype.Component;importjava.util.List;@Component@ConfigurationProperties(prefix ="library")@Setter@Getter@ToStringclassLibraryPropertiesprivateString location;privateList books;@Setter@Getter@ToStringstaticclassBook        String name;        String description;   

这个时候你就可以像使用普通 bean 一样,将其注入到类中使用:

packagecn.javaguide.readconfigproperties;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/** *@authorshuang.kou */@SpringBootApplicationpublicclassReadConfigPropertiesApplicationimplementsInitializingBeanprivatefinalLibraryProperties library;publicReadConfigPropertiesApplication(LibraryProperties library)this.library = library;    publicstaticvoidmain(String[] args)        SpringApplication.run(ReadConfigPropertiesApplication.class,args);    @OverridepublicvoidafterPropertiesSet()        System.out.println(library.getLocation());        System.out.println(library.getBooks());   

控制台输出:

湖北武汉加油中国加油[LibraryProperties.Book(name=天才基本法, description........]

3.通过@ConfigurationProperties读取并校验

我们先将application.yml修改为如下内容,明显看出这不是一个正确的 email 格式:

my-profile:name: Guide哥email: koushuangbwcx@

ProfileProperties 类没有加 @Component 注解。我们在我们要使用ProfileProperties 的地方使用@

EnableConfigurationProperties注册我们的配置 bean:

importlombok.Getter;importlombok.Setter;importlombok.ToString;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.stereotype.Component;importorg.springframework.validation.annotation.Validated;importjavax.validation.constraints.Email;importjavax.validation.constraints.NotEmpty;/***@authorshuang.kou*/@Getter@Setter@ToString@ConfigurationProperties("my-profile")@ValidatedpublicclassProfileProperties@NotEmptyprivateString name;@Email@NotEmptyprivateString email;//配置文件中没有读取到的话就用默认值privateBooleanhandsome =Boolean.TRUE;

具体使用:

packagecn.javaguide.readconfigproperties;importorg.springframework.beans.factory.InitializingBean;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.context.properties.EnableConfigurationProperties;/** *@authorshuang.kou */@SpringBootApplication@EnableConfigurationProperties(ProfileProperties.class)publicclassReadConfigPropertiesApplicationimplementsInitializingBeanprivatefinalProfileProperties profileProperties;publicReadConfigPropertiesApplication(ProfileProperties profileProperties)this.profileProperties = profileProperties;    publicstaticvoidmain(String[] args)        SpringApplication.run(ReadConfigPropertiesApplication.class,args);    @OverridepublicvoidafterPropertiesSet()        System.out.println(profileProperties.toString());   

因为我们的邮箱格式不正确,所以程序运行的时候就报错,根本运行不起来,保证了数据类型的安全性:

Binding to target org.springframework.boot.context.properties.bind.BindException:Failedtobindpropertiesunder'my-profile'to cn.javaguide.readconfigproperties.ProfileProperties failed:Property:my-profile.emailValue:koushuangbwcx@Origin:classpathresource[application.yml]:5:10Reason:mustbeawell-formedemailaddress

我们把邮箱测试改为正确的之后再运行,控制台就能成功打印出读取到的信息:

ProfileProperties(name=Guide哥, email=koushuangbwcx@163.com, handsome=true)

4.@PropertySource读取指定 properties 文件

importlombok.Getter;importlombok.Setter;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.PropertySource;importorg.springframework.stereotype.Component;@Component@PropertySource("classpath:website.properties")@Getter@SetterclassWebSite@Value("$url")privateString url;

使用:

@Autowiredprivate WebSite webSite;System.out.println(webSite.getUrl());//https://javaguide.cn/

5.题外话:Spring 加载配置文件的优先级

Spring 读取配置文件也是有优先级的,直接上图:

原文链接:https://www.toutiao.com/a6791445278911103500/?log_from=7f5fb8f9b4b47_1640606437752

SpringBoot启动时如何对配置文件进行校验?这种方法才叫优雅~

概述

在项目开发过程中,某个功能需要依赖在配置文件中配置的参数。这时候就可能出现下面这种现象:

有时候经常出现项目启动了,等到使用某个功能组件的时候出现异常,提示参数未配置或者bean注入失败。

那有没有一种方法在项目启动时就对参数进行校验而不是在实际使用的时候再抛出提示呢?

当然可以,答案就是使用Spring提供的Java Validation功能,简单实用。

Validation不是做参数校验的吗?居然还可以干这种事!

开启启动时参数校验

只需要在我们创建的配置Properties类增加Validation相关配置即可

@Validated
@Data
@ConfigurationProperties(prefix = "app")
@Component
public class AppConfigProperties 
    @NotEmpty(message = "配置文件配置必须要配置[app.id]属性")
    private String id;

上面的配置就会校验我们在 application.yml中有没有配置 app.id参数。如果在配置文件中没有该配置,项目启动就会失败,并抛出校验异常。

在使用配置文件校验时,必须使用@configurationproperties注解,@value注解不支持该功能。

在需要使用app.id的时候注入配置类即可:

@Autowired
private AppConfigProperties appConfigProperties;

这样就可以实现我们想要的效果,如下图:

支持校验类型

校验规则规则说明
@Null限制只能为null
@NotNull限制必须不为null
@AssertFalse限制必须为false
@AssertTrue限制必须为true
@DecimalMax(value)限制必须为一个不大于指定值的数字
@DecimalMin(value)限制必须为一个不小于指定值的数字
@Digits(integer,fraction)限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future限制必须是一个将来的日期
@Max(value)限制必须为一个不大于指定值的数字
@Min(value)限制必须为一个不小于指定值的数字
@Past验证注解的元素值(日期类型)比当前时间早
@Pattern(value)限制必须符合指定的正则表达式
@Size(max,min)限制字符长度必须在min到max之间
@NotEmpty验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

Validation 支持如下几种校验,可以满足基本的业务逻辑,当然如果还是满足不了你的业务逻辑,可以选择定制校验规则。

定制校验逻辑

  1. 定义校验逻辑规则,实现org.springframework.validation.Validator

public class ConfigPropertiesValidator implements Validator 
    @Override
    public boolean supports(Class<?> aClass) 
        return AppConfigProperties.class.isAssignableFrom(aClass);
    

    @Override
    public void validate(Object o, Errors errors) 
        AppConfigProperties config = (AppConfigProperties) o;
        if(StringUtils.isEmpty(config.getId()))
            errors.rejectValue("id", "app.id.empty", "[app.id] 属性必须要在配置文件配置");
        else if (config.getId().length() < 5) 
            errors.rejectValue("id", "app.id.short", "[app.id] 属性的长度必须不能小于5");
        
    
  1. 使用自定义校验规则就不需要再使用原生的@NotEmpty了,将其删除

@Validated
@Data
@ConfigurationProperties(prefix = "app")
@Component
public class AppConfigProperties 
//    @NotEmpty(message = "配置文件配置必须要配置[app.id]属性")
    private String id;
  1. 注入自定义校验规则

@Bean
public  ConfigPropertiesValidator configurationPropertiesValidator()
  return new ConfigPropertiesValidator();

注意:这里bean的方法名必须要使用 configurationPropertiesValidator,否则启动的时候不会执行该校验

  1. 修改app.id配置,观察启动情况

错误信息即为我们自定义校验的结果。

小结

通过配置Spring Boot启动校验功能,可以快速的识别参数配置的错误,避免在使用组件的时候才发现问题,可以减少排查问题的工作量,并且在我们封装自定义starter时可以有更好的体验。试想一下,你们很多项目共用部门一个Redis集群,那不同项目之间肯定要进行key隔离,这时候你提供一个公共的redis starter,强制必须在使用时指定app.id作为redis的自定义key前缀,岂不是会受到领导大大的赞美?

以上是关于SpringBoot 如何优雅读取配置文件?10分钟教你搞定的主要内容,如果未能解决你的问题,请参考以下文章

优雅写代码系统springboot+mybatis+pagehelper+mybatisplus+druid教你如何优雅写代码

补习系列(10)-springboot 之配置读取

SpringBoot启动时如何对配置文件进行校验?这种方法才叫优雅~

SpringBoot启动时如何对配置文件进行校验?这种方法才叫优雅!(文末福利)

SpringBoot读取配置文件的三种方法

SpringBoot项目优雅的实现多配置文件切换以及获取配置信息