SpringBoot中5种高大上的yml文件读取方式

目录
  • 1、Environment
  • 2、YamlPropertiesFactoryBean
  • 3、监听事件
  • 4、SnakeYml
  • 5、jackson-dataformat-yaml
  • 总结

在上一篇文章中,我们从源码角度分析了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<String, Object> 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<ApplicationEnvironmentPreparedEvent> {
    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<PropertySource<?>> 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前加一个断点,查看环境的变化:

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

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

susan
female

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

4、SnakeYml

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

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.23</version>
</dependency>

准备一个yml配置文件:

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

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

public void test1(){
    Yaml yaml=new Yaml();
    Map<String, Object> 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文件进行修改:

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

在添加了连接符后,尝试再使用load方法进行解析,报错如下显示发现了另一段yml文档从而无法正常解析:

这时候修改上面的代码,使用loadAll方法:

public void test2(){
    Yaml yaml=new Yaml();
    Iterable<Object> objects =
        yaml.loadAll(getClass().getClassLoader()
            .getResourceAsStream("snake2.yml"));
    for (Object object : objects) {
        System.out.println(object);
    }
}

执行结果如下:

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

可以看到,loadAll方法返回的是一个对象的迭代,里面的每个对象对应yml中的一段文档,修改后的yml文件就被解析成了两个独立的Map。

接下来再来看一下loadAs方法,它可以在yml解析过程中指定类型,直接封装成一个对象。我们直接复用上面的snake1.yml,在解析前先创建两个实体类对象用于接收:

@Data
public class Person {
    SinglePerson person1;
    SinglePerson person2;
}

@Data
public class SinglePerson {
    String name;
    String gender;
}

下面使用loadAs方法加载yml,注意方法的第二个参数,就是用于封装yml的实体类型。

public void test3(){
    Yaml yaml=new Yaml();
    Person person = 
        yaml.loadAs(getClass().getClassLoader().
            getResourceAsStream("snake1.yml"), Person.class);
    System.out.println(person.toString());
}

查看执行结果:

Person(person1=SinglePerson(name=hydra, gender=male), person2=SinglePerson(name=susan, gender=female))

实际上,如果想要将yml封装成实体对象,也可以使用另一种方法。在创建Yaml对象的时候,传入一个指定实体类的构造器对象,然后直接调用load方法就可以实现:

public void test4(){
    Yaml yaml=new Yaml(new Constructor(Person.class));
    Person person = yaml.load(getClass().getClassLoader().
            getResourceAsStream("snake1.yml"));
    System.out.println(person.toString());
}

执行结果与上面相同:

Person(person1=SinglePerson(name=hydra, gender=male), person2=SinglePerson(name=susan, gender=female))

SnakeYml其实实现了非常多的功能,这里就不一一列举了,有兴趣的小伙伴可以自己查看一下文档。如果你看了上一篇的文章后跟着翻阅了一下源码,那么你会发现,其实在SpringBoot的底层,也是借助了SnakeYml来进行的yml的解析操作。

5、jackson-dataformat-yaml

相比大家平常用jackson比较多的场景是用它来处理json,其实它也可以用来处理yml,使用前需要引入依赖:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.12.3</version>
</dependency>

使用jackson读取yml也非常简单,这里用到了常用的ObjectMapper,在创建ObjectMapper对象时指定使用YAML工厂,之后就可以简单的将yml映射到实体:

public void read() throws IOException {
    ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
    InputStream input =
        new FileInputStream("F:\\Work\\yml\\src\\main\\resources\\snake1.yml");
    Person person = objectMapper.readValue(input, Person.class);
    System.out.println(person.toString());
}

运行结果:

Person(person1=SinglePerson(name=hydra, gender=male), person2=SinglePerson(name=susan, gender=female))

如果想要生成yml文件的话,可以调用ObjectMapper的writeValue方法实现:

public void write() throws IOException {
    Map<String,Object> map=new HashMap<>();
    SinglePerson person1 = new SinglePerson("Trunks", "male");
    SinglePerson person2 = new SinglePerson("Goten", "male");
    Person person=new Person(person1,person2);
    map.put("person",person);

    ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
    objectMapper
            .writeValue(new File("F:\\Work\\yml\\src\\main\\resources\\jackson-gen.yml"),map);
}

查看生成的yml文件,可以看到jackson对字符串类型严格的添加了引号,还在文档的开头添加了yml的链接符。至于其他jackson读写yml的复杂功能,大家可以在工作中自己去探索使用。

总结

本文介绍了5种读取yml配置文件的方式,前3种依赖于Spring环境,而SnakeYml和Jackson则可以脱离环境独立使用,可以说它们是对@Value和@ConfigurationProperties注解使用的补充。这几种方法的使用场景不同,也各有各的优点,各自具备一些特殊的用法,而我们在工作中更多情况下,要根据具体的用途进行一种方案的选取或多种的搭配使用。

到此这篇关于SpringBoot中5种高大上的yml文件读取方式的文章就介绍到这了,更多相关SpringBoot yml文件读取方式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Springboot yml Map List读取方式

    目录 Springboot yml Map List读取 1.配置类集中放置 2.配置类单独放置 3.List读取 4.问题:配置类没有获取到值 Springboot yml内list.map组合写法 Springboot yml Map List读取 Springboot 读取yml中的值作为参数,有2种写法: 例子: 已知有如下yml配置:   myapps:     1131f78c313e11e79da3000c298bdf0e: AMS系统     1ae211c543a14cf698

  • springboot中.yml文件参数的读取方式

    目录 yml文件参数的读取 附上一个较为常见的application.yml文件示例 正常在controller中 通过config文件的读取 关于yml文件书写的注意事项 yml文件参数的读取 附上一个较为常见的application.yml文件示例 server: port: 9999 use-forward-headers: true tomcat: remote-ip-header: X-Real-IP protocol-header: X-Forwarded-Proto spring:

  • SpringBoot中5种高大上的yml文件读取方式

    目录 1.Environment 2.YamlPropertiesFactoryBean 3.监听事件 4.SnakeYml 5.jackson-dataformat-yaml 总结 在上一篇文章中,我们从源码角度分析了SpringBoot解析yml配置文件的全流程,那么我们今天就来点实战,总结一下除了烂大街的@Value和@ConfigurationProperties外,还能够通过哪些方式,来读取yml配置文件的内容. 1.Environment 在Spring中有一个类Environmen

  • GO语言常用的文件读取方式

    本文实例讲述了GO语言常用的文件读取方式.分享给大家供大家参考.具体分析如下: Golang 的文件读取方法很多,刚上手时不知道怎么选择,所以贴在此处便后速查. 一次性读取 小文件推荐一次性读取,这样程序更简单,而且速度最快. 复制代码 代码如下: func ReadAll(filePth string) ([]byte, error) {  f, err := os.Open(filePth)  if err != nil {   return nil, err  } return iouti

  • 将tensorflow模型打包成PB文件及PB文件读取方式

    1. tensorflow模型文件打包成PB文件 import tensorflow as tf from tensorflow.python.tools import freeze_graph with tf.Graph().as_default(): with tf.device("/cpu:0"): config = tf.ConfigProto(allow_soft_placement=True) with tf.Session(config=config).as_defaul

  • 使用springboot打包后的文件读取方式

    目录 springboot打包后的文件读取 文件打包问题 文件读取问题 Springboot打包后读取不到文件 解决办法1 失败.. 解决办法 2 springboot打包后的文件读取 在使用了springboot打包后的项目中,牵扯到项目目录中文件读取工作时,明明在开发时功能正常,但是一到发布到线上环境就会报文件找不到,路径不存在的问题. 由于在开发过程中,文件就在我们本地目录中存在,因此普通正常文件的读写功能不受影响,而一旦打包后,可能会由于我们自己的文件目录放置原因一是没有被正确打包到ja

  • docker-compose安装yml文件配置方式

    目录 1.离线安装 2.在线安装 3.卸载 4.定义yml文件 1.离线安装 https://github.com/docker/compose/releases 移动文件 mv docker-compose-linux-x86_64 /usr/local/bin 修改文件名 mv docker-compose-linux-x86_64 docker-compose 给docker-compose赋予执行权限 .默认没有执行权限. chmod -x docker-compose 检测是否成功 d

  • JavaScript中三种异步上传文件方式

    异步上传文件是为了更好的用户体验,是每个前端必须掌握的技能.这里我提出三点有关异步文件上传的方式. 使用第三方控件,如Flash,ActiveX等浏览器插件上传. 使用隐藏的iframe模拟异步上传. 使用XMLHttpRequest2来实现异步上传. 第一种使用浏览器插件上传,需要一定的底层编码功底,在这里我就不讲了,以免误人子弟,提出这点大家可以自行百度. 第二种使用隐藏的iframe模拟异步上传.为什么在这里说的是模拟呢?因为我们其实是将返回结果放在了一个隐藏的iframe中,所以才没有使

  • 三种Node.js写文件的方式

    本文分享了Node.js写文件的三种方式,具体内容和如下 1.通过管道流写文件 采用管道传输二进制流,可以实现自动管理流,可写流不必当心可读流流的过快而崩溃,适合大小文件传输(推荐) var readStream = fs.createReadStream(decodeURIComponent(root + filepath.pathname)); // 必须解码url readStream.pipe(res); // 管道传输 res.writeHead(200,{ 'Content-Type

  • SpringBoot项目application.yml文件数据库配置密码加密的方法

    在Spring boot开发中,需要在application.yml文件里配置数据库的连接信息,或者在启动时传入数据库密码,如果不加密,传明文,数据库就直接暴露了,相当于"裸奔"了,因此需要进行加密处理才行. 使用@SpringBootApplication注解启动的项目,只需增加maven依赖 我们对信息加解密是使用这个jar包的: 编写加解密测试类: package cn.linjk.ehome; import org.jasypt.encryption.pbe.StandardP

  • springboot+mybatis-plus 两种方式打印sql语句的方法

    1.注解方式,yml文件配置上以下就可以直接使用 mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 2.这一种网上没有,搜过好多资料都没有,我是配置多数据源,所以是在代码中写的config那么yml文件就是失效的,只能一个一个配置,到了打印sql的时候,就怎么都是找不到,后来设置的源码找到灵感,发现可

  • springboot中项目启动时实现初始化方法加载参数

    目录 springboot项目启动,初始化方法加载参数 1.@PostConstruct说明 2.@PreDestroy说明 第一种:注解@PostConstruct 第二种:实现CommandLineRunner接口 第三种:springboot的启动类 springboot初始化参数顺序 spring初始化参数顺序为 springboot项目启动,初始化方法加载参数 今天我看到项目中用到了 @PostConstruct 这个注解,之前没看到过,特地查了一下, 1.@PostConstruct

随机推荐