5种高大上的yml文件读取方式,你知道吗?

原创:微信公众号 码农参上,欢迎分享,转载请保留出处。

在上一篇文章中,我们从源码角度分析了SpringBoot解析yml配置文件的全流程,那么我们今天就来点实战,总结一下除了烂大街的 @Value@ConfigurationProperties外,还能够通过哪些方式,来读取yml配置文件的内容。

1、Environment

在Spring中有一个类 Environment,它可以被认为是当前应用程序正在运行的环境,它继承了 PropertyResolver接口,因此可以作为一个属性解析器使用。先创建一个yml文件,属性如下:

person:
  name: hydra
  gender: male
  age: 18

使用起来也非常简单,直接使用 @Autowired就可以注入到要使用的类中,然后调用它的 getProperty()方法就可以根据属性名称取出对应的值了。

@RestController
public class EnvironmentController {
    @Autowired
    private Environment environment;

    @GetMapping("envTest")
    private void getEnv(){
        System.out.println(environment.getProperty("person.name"));
        System.out.println(environment.getProperty("person.gender"));

        Integer autoClose = environment
            .getProperty("person.age", Integer.class);
        System.out.println(autoClose);
        String defaultValue = environment
            .getProperty("person.other", String.class, "defaultValue");
        System.out.println(defaultValue);
    }
}

在上面的例子中可以看到,除了简单的获取外, Environment提供的方法还可以对取出的属性值进行类型转换、以及默认值的设置,调用一下上面的接口,打印结果如下:

hydra
male
18
defaultValue

除了获取属性外,还可以用来判断激活的配置文件,我们先在 application.yml中激活 pro文件:

spring:
  profiles:
    active: pro

可以通过 acceptsProfiles方法来检测某一个配置文件是否被激活加载,或者通过 getActiveProfiles方法拿到所有被激活的配置文件。测试接口:

@GetMapping("getActiveEnv")
private void getActiveEnv(){
    System.out.println(environment.acceptsProfiles("pro"));
    System.out.println(environment.acceptsProfiles("dev"));

    String[] activeProfiles = environment.getActiveProfiles();
    for (String activeProfile : activeProfiles) {
        System.out.println(activeProfile);
    }
}

打印结果:

true
false
pro

2、YamlPropertiesFactoryBean

在Spring中还可以使用 YamlPropertiesFactoryBean来读取自定义配置的yml文件,而不用再被拘束于 application.yml及其激活的其他配置文件。

在使用过程中,只需要通过 setResources()方法设置自定义yml配置文件的存储路径,再通过 getObject()方法获取 Properties对象,后续就可以通过它获取具体的属性,下面看一个例子:

@GetMapping("fcTest")
public void ymlProFctest(){
    YamlPropertiesFactoryBean yamlProFb = new YamlPropertiesFactoryBean();
    yamlProFb.setResources(new ClassPathResource("application2.yml"));
    Properties properties = yamlProFb.getObject();
    System.out.println(properties.get("person2.name"));
    System.out.println(properties.get("person2.gender"));
    System.out.println(properties.toString());
}

查看运行结果,可以读取指定的 application2.yml的内容:

susan
female
{person2.age=18, person2.gender=female, person2.name=susan}

但是这样的使用中有一个问题,那就是只有在这个接口的请求中能够取到这个属性的值,如果再写一个接口,不使用 YamlPropertiesFactoryBean读取配置文件,即使之前的方法已经读取过这个yml文件一次了,第二个接口取到的仍然还是空值。来对这个过程进行一下测试:

@Value("${person2.name:null}")
private String name;
@Value("${person2.gender:null}")
private String gender;

@GetMapping("fcTest2")
public void ymlProFctest2(){
    System.out.println(name);
    System.out.println(gender);
}

先调用一次 fcTest接口,再调用 fcTest2接口时会打印 null值:

null
null

想要解决这个问题也很简单,可以配合 PropertySourcesPlaceholderConfigurer使用,它实现了 BeanFactoryPostProcessor接口,也就是一个bean工厂后置处理器的实现,可以将配置文件的属性值加载到一个 Properties文件中。使用方法如下:

@Configuration
public class PropertyConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer
            = new PropertySourcesPlaceholderConfigurer();
        YamlPropertiesFactoryBean yamlProFb
            = new YamlPropertiesFactoryBean();
        yamlProFb.setResources(new ClassPathResource("application2.yml"));
        configurer.setProperties(yamlProFb.getObject());
        return configurer;
    }
}

再次调用之前的接口,结果如下,可以正常的取到 application2.yml中的属性:

susan
female

除了使用 YamlPropertiesFactoryBean将yml解析成 Properties外,其实我们还可以使用 YamlMapFactoryBean解析yml成为 Map,使用方法非常类似:

@GetMapping("fcMapTest")
public void ymlMapFctest(){
    YamlMapFactoryBean yamlMapFb = new YamlMapFactoryBean();
    yamlMapFb.setResources(new ClassPathResource("application2.yml"));
    Map map = yamlMapFb.getObject();
    System.out.println(map);
}

打印结果:

{person2={name=susan, gender=female, age=18}}

3、监听事件

在上篇介绍原理的文章中,我们知道SpringBoot是通过监听事件的方式来加载和解析的yml文件,那么我们也可以仿照这个模式,来加载自定义的配置文件。

首先,定义一个类实现 ApplicationListener接口,监听的事件类型为 ApplicationEnvironmentPreparedEvent,并在构造方法中传入要解析的yml文件名:

public class YmlListener implements
    ApplicationListener {
    private String ymlFilePath;
    public YmlListener(String ymlFilePath){
        this.ymlFilePath = ymlFilePath;
    }
    //...

}

自定义的监听器中需要实现接口的 onApplicationEvent()方法,当监听到 ApplicationEnvironmentPreparedEvent事件时会被触发:

@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    ConfigurableEnvironment environment = event.getEnvironment();
    ResourceLoader loader = new DefaultResourceLoader();
    YamlPropertySourceLoader ymlLoader = new YamlPropertySourceLoader();
    try {
        List> sourceList = ymlLoader
            .load(ymlFilePath, loader.getResource(ymlFilePath));
        for (PropertySource propertySource : sourceList) {
            environment.getPropertySources().addLast(propertySource);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

上面的代码中,主要实现了:

  • 获取当前环境 Environment,当 ApplicationEnvironmentPreparedEvent事件被触发时,已经完成了 Environment的装载,并且能够通过 event事件获取
  • 通过 YamlPropertySourceLoader加载、解析配置文件
  • 将解析完成后的 OriginTrackedMapPropertySource添加到 Environment

修改启动类,在启动类中加入这个监听器:

public static void main(String[] args) {
    SpringApplication application = new SpringApplication(MyApplication.class);
    application.addListeners(new YmlListener("classpath:/application2.yml"));
    application.run(args);
}

在向 environment中添加 propertySource前加一个断点,查看环境的变化:

5种高大上的yml文件读取方式,你知道吗?

执行完成后,可以看到配置文件源已经被添加到了环境中:

5种高大上的yml文件读取方式,你知道吗?

启动完成后再调用一下接口,查看结果:

susan
female

能够正确的取到配置文件中的值,说明自定义的监听器已经生效。

4、SnakeYml

前面介绍的几种方式,在Spring环境下无需引入其他依赖就可以完成的,接下来要介绍的 SnakeYml在使用前需要引入依赖,但是同时也可以脱离Spring环境单独使用。先引入依赖坐标:


    org.yaml
    snakeyaml
    1.23

准备一个yml配置文件:

person1:
  name: hydra
  gender: male
person2:
  name: susan
  gender: female

在使用 SnakeYml解析yml时,最常使用的就是 loadloadlAllloadAs方法,这三个方法可以加载yml文件或字符串,最后返回解析后的对象。我们先从基础的 load方法开始演示:

public void test1(){
    Yaml yaml=new Yaml();
    Map map =
            yaml.load(getClass().getClassLoader()
                    .getResourceAsStream("snake1.yml"));
    System.out.println(map);
}

运行上面的代码,打印Map中的内容:

{person1={name=hydra, gender=male}, person2={name=susan, gender=female}}

接下来看一下 loadAll方法,它可以用来加载yml中使用 ---连接符连接的多个文档,将上面的yml文件进行修改:

`yml
person1:
name: hydra
gender: male

Original: https://www.cnblogs.com/trunks2008/p/15829085.html
Author: 码农参上
Title: 5种高大上的yml文件读取方式,你知道吗?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/573398/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • CAS底层原理与ABA问题

    CAS定义 CAS(Compare And Swap)是一种无锁算法。CAS算法是乐观锁的一种实现。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当预期值A和内存值V…

    Java 2023年6月7日
    080
  • 通用树形结构的迭代与组合模式实现方案

    日常开发过程过程中。树形结构运用的非常频繁。 例如:公司组织结构、各种分类结构、分组结构等等。 SET FOREIGN_KEY_CHECKS = 0; CREATE TABLE I…

    Java 2023年6月9日
    0114
  • 使用docker部署poetry管理的项目

    前言 poetry是和 virtualenv pipenv一样的包管理工具, 其使用方式类似于 npm我们使用 poetry创建虚拟环境后会生成 poetry.lock和 pypr…

    Java 2023年6月7日
    089
  • 树莓派修改分辨率

    树莓派屏幕分辨率设置 树莓派一般第一次开机会自动给显示屏分配一个最合适的分辨率,但是有时候可能有个别显示屏会不兼容,就需要通过以下方式修改分辨率。而当我们使用VNC远程桌面登录的时…

    Java 2023年5月30日
    096
  • Dubbo本地开发技巧

    作为后端服务负载、前后分离的主要手段,dubbo在业界中使用率还比较高。随着Dubbo系统的增多,本地开发、调试就出现了麻烦之处 直接在开发本地起同样一份服务 由于Dubbo采用负…

    Java 2023年6月7日
    0101
  • JAVA中Integer的==和equals注意

    “equals”比较equals(Object obj)方法,在equals(Object obj)方法中,会先判断参数中的对象obj是否是Integer同…

    Java 2023年5月29日
    079
  • redis-SpringBoot(21)

    Redis是大规模互联网应用常用的内存高速缓存数据库,它的读写速度非常快,据官方 Bench-mark的数据,它读的速度能到11万次/秒,写的速度是8.1万次/秒。 认识Sprin…

    Java 2023年6月13日
    066
  • 每日一考-9.15

    wait和sleep的区别 简说:wait释放🔒,sleep不释放🔒 例子:买票过程中,当程序进行上锁后 sleep控制下的线程,买票是一一完成,当程序休眠后,sleep不会释放🔒…

    Java 2023年6月16日
    068
  • SpringBoot使用Filter

    对全部请求进行Filter Filter: package com.example.demo.filter; import org.springframework.core.Ord…

    Java 2023年6月9日
    074
  • Java 操作 XML(14)–jackson-dataformat-xml 使用

    Jackson 除了可以处理 JSON,还可以用来处理 XML(jackson-dataformat-xml 模块),可以轻松完成 Java 对象和 XML 文档的互转;本文主要介…

    Java 2023年6月16日
    082
  • 【Java】【53】map的containsKey()及containsValue()方法

    前言: containsKey():map中是否包含某个key值 containsValue():map中是否包含某个value值 正文: 参考博客: Original: http…

    Java 2023年5月29日
    0103
  • 深入Java微服务之网关系列1:什么是网关

    ​ 前言 近来,在想着重构一个新的产品。准备采用微服务的技术解决方案,来搭建基础设施框架。网关,是一个必不可少的组件。那么,网关到底是什么? 其又有什么特点或者特性,成为微服务必不…

    Java 2023年5月29日
    086
  • Java学习-第一部分-第三阶段-第一节:网络编程

    网络编程 笔记目录:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 网络基础 网络通信 概念:两台设备之间通过网络实现数据…

    Java 2023年6月15日
    060
  • Java的jstat命令使用详解

    jstat命令简介 jstat(Java Virtual Machine Statistics Monitoring Tool)是JDK提供的一个可以监控Java虚拟机各种运行状态…

    Java 2023年6月7日
    0127
  • CAS 单点登录【1】入门

    很早期的公司,一家公司可能只有一个应用,慢慢的应用开始变多,如员工报销系统、审核系统、学习系统…… 每个应用都要进行注册登录,退出的时候又要一个个退出,用户…

    Java 2023年5月29日
    081
  • SpringCloud微服务实战——搭建企业级开发框架(四十一):扩展JustAuth+SpringSecurity+Vue实现多租户系统微信扫码、钉钉扫码等第三方登录

    前面我们详细介绍了SSO、OAuth2的定义和实现原理,也举例说明了如何在微服务框架中使用spring-security-oauth2实现单点登录授权服务器和单点登录客户端。目前很…

    Java 2023年6月9日
    081
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球