SpringBoot读取Properties和Yaml文件

1 序

SpringBoot.jpg
  • 示例代码(maven分支,load-properties模块):https://gitee.com/eugene-example/springboot
  • 首先,我们通常读取的配置文件是指propertiesyaml两类。无论是使用Maven还是Gradle工具来构建,我们读取都是基于类路径,也就是工程resources目录下存放的文件。本文先讲解读取properties类型的配置文件。
  • SpringBoot配置文件,例如工程resources目录下存放的:bootstrap.propertiesapplication.propertiesapplication-dev.propertiesapplication-prod.properties
  • 用户自定义的配置文件,例如工程resources目录下存放的:config.propertiesdb/ds.properties
  • Spring Framework相关注解说明:
    • @PropertySource注解,使用value属性,来指定加载类路径下的properties文件,读取SpringBoot配置文件时无需使用此注解,直接通过@Value注解读取即可。
    • @Value注解,通过表达式${key.key...}直接读取SpringBoot配置文件的属性。或者结合@ConfigurationProperties注解使用。同时也可使用表达式#{object.prop}来读取对象属性。
    • @ConfigurationProperties注解,使用prefix属性指定读取属性的前缀,可配合@Value注解使用,便于简化读取属性表达式。

2 示例展示

2.1 使用的示例文件

  • SpringBoot配置文件:resource\application.properties,内容如下:
server.port=9999
  • 类路径下的用户自定义配置文件:resource\config.properties,内容如下:
user.name=EugeneHeen
user.password=12345678
  • 类路径下自定义目录存放的用户自定义配置文件:resource\db\ds.yml,内容如下:
ds:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://127.0.0.1:3306/eugene
  username: root
  password: 88888888
  pool:
    name: ds-poll
    select: SELECT 1 FROM A

2.2 读取SpringBoot规范的默认配置文件

  1. 通过定义一个POJO封装SpringBoot配置文件的属性读取
@Data // 通过Lombok提供GET和SET方法
@ConfigurationProperties(prefix = "server")
@Component
public class BootProps {
    private Integer port;
}

@RestController
@RequestMapping("/boots")
public class BootController {

    @Autowired
    private BootProps bootProps;

    @Value("${server.port}")
    private String port;

    @GetMapping("/auth")
    public String auth() {
        return new StringBuilder("SpringBoot Server Port")
                .append(": ")
                .append(this.port)
                .append(", 通过封装Bean获取Port:")
                .append(this.bootProps.getPort()).toString();
    }
}
  1. 直接在使用的类中通过@Value注解标记示例变量读取,例如,ControllerService
@RestController
@RequestMapping("/configs")
public class BootController {
    @Value("${server.port}")
    private Integer port;
    
    @GetMapping("/value")
    public String value() {
        return new StringBuilder("SpringBoot Server Port")
                .append(": ")
                .append(this.port).toString();
     }
 }

2.3 读取用户自定义的配置文件

  1. 通过定义一个POJO类 ,@PropertySource + @Value注解来读取
@Data
@PropertySource(value = {"config.properties"})
@Component
public class ConfigProps {
    @Value("${user.name}")
    private String name;
    @Value("${user.password}")
    private String password;
}
  • 通过定义一个POJO类 ,@PropertySource + @ConfigurationProperties注解来简化读取,也可配合@Value注解使用。这种方法对YAML文件无效,后续会通过详细示例阐述如何解决此问题
@Data
@PropertySource(value = {"db/ds.properties"})
@ConfigurationProperties(prefix = "master")
@Component
public class DsProps {
    private String username;

    private String password;
}

经实际测试,SpringBoot2.3+的版本,会自动将配置文件中的单词-连接的属性,同自定义POJO类中遵循驼峰命名的属性匹配,无需使用@Value注解来完成值读取。例如,1. 配置文件username自动对应POJO类中的userName属性。2. 配置文件driver-class-name自动对应POJO类中的driverClassName属性。

3 读取用户自定义YAML文件

3.1 User Define YAML,SpringBoot Say No!我不支持下面这些骚操作

  1. @PropertySource + @Value注解
  2. @PropertySource + @ConfigurationProperties注解

Tip:@PropertySource不支持YAML文件加载,它仅仅支持Properties文件加载

3.2 单层级YAML配置文件读取

  1. 单层级 VS 多层级
    • 但层级配置文件
      ds:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/eugene
          username: root
          password: 88888888
      
    • 多层级配置文件
      ds:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/eugene
          username: root
          password: 88888888
          pool:
              name: ds-poll
              select: SELECT 1 FROM A
      
  2. 通过定义一个POJO类 ,@PropertySource + @ConfigurationProperties + @Value注解来实现单层级YAML配置文件读取
@Data
@PropertySource(value = {"db/ds.yml"})
@ConfigurationProperties(prefix = "ds")
@Component
public class DsYaml {
    @Value("${driver-class-name}")
    private String driverClassName;

    @Value("${username}")
    private String userName;

    @Value("${password}")
    private String password;
}

3.3 多层级YAML配置文件读取

  1. User Define YAML,SpringBoot Only Supports!我仅支持唯一的骚操作

    • @PropertySource指定factory属性为自定义DefaultPropertySourceFactory的扩展类 + @Value注解(别再瞎搞!切记!此处无法再使用@ConfigurationProperties注解的prefix属性指定前缀了)
  2. 关于Spring Framework中与配置文件相关的3个类:

    • YamlPropertiesFactoryBean:用于将YAML文件加载为Properties文件。
    • YamlMapFactoryBean:用于将YAML文件加载为Map对象。
    • DefaultPropertySourceFactory@PropertySource注解中的factory属性默认使用的实现类。
  3. 扩展DefaultPropertySourceFactory类,自定义YAML文件加载工厂类

public class YamlPropertySourceFactory extends DefaultPropertySourceFactory {
    public YamlPropertySourceFactory() {
        super();
    }

    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = Optional.ofNullable(name).orElse(resource.getResource().getFilename());
        if (!resource.getResource().exists()) {
            // return an empty Properties
            return new PropertiesPropertySource(sourceName, new Properties());
        } else if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
            Properties propertiesFromYaml = loadYaml(resource);
            return new PropertiesPropertySource(sourceName, propertiesFromYaml);
        } else {
            return super.createPropertySource(name, resource);
        }
    }

    /**
     * 加载YAML文件
     * @param resource YAML文件
     * @return Properties对象
     * @throws IOException 文件加载异常
     */
    private Properties loadYaml(EncodedResource resource) throws IOException {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(resource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
}
  1. 加载多层级YAML配置文件
@Data
@PropertySource(factory = YamlPropertySourceFactory.class, value = {"db/ds.yml"})
@Component
public class DsAYaml {
    @Value("${ds.driver-class-name}")
    private String driverClassName;

    @Value("${ds.username}")
    private String userName;

    @Value("${ds.password}")
    private String password;

    @Value("${ds.pool.name}")
    private String poolName;

    @Value("${ds.pool.select}")
    private String poolSelect;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容