欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

@PropertySource 解析 yml 配置文件,自定义解析 yaml 工厂类

程序员文章站 2022-05-02 12:27:12
...

自定义解析 yaml 工厂类,YamlPropertySourceFactory

参考代码,见 github:
https://github.com/tudan110/learn-dev-tools

@PropertySource 注解

使用 @PropertySource 注解,可以编写配置文件的映射类,取代 @Value,在需要用到的地方,用 @Autowire 自动装配配置类即可。

源码如下
public @interface PropertySource {
    
    /** 加载资源的名称 */
    String name () default "";

    /** 
     * 加载资源的路径,可使用 classpath, 如: 
     *      "classpath:/config/test.yml"
     *  如有多个文件路径放在 {} 中,使用 ',' 号隔开,如:
     *      {"classpath:/config/test1.yml","classpath:/config/test2.yml"}
     *  除使用 classpath 外,还可使用文件的地址,如:
     *      "file:/rest/application.properties"
     */
    String [] value ();
    
    /** 此属性为根据资源路径找不到文件后是否报错,默认为是 false */
    boolean ignoreResourceNotFound () default false;

    /** 此为读取文件的编码,若配置中有中文建议使用 'utf-8' */
    String encoding () default "";
    
    /**
     *  关键:此为读取资源文件的工程类,默认为:
     *        'PropertySourceFactory.class'
     */
    Class<? extends PropertySourceFactory> factory () default PropertySourceFactory.class;
}

其中 factory () 指定了解析配置文件的工厂类

使用参考示例,如下

@PropertySource (
        name = "test.properties",
        value = {"classpath:config/test.properties"},
        ignoreResourceNotFound = false,
        encoding = "UTF-8",
        factory = DefaultPropertySourceFactory.class
)

PropertySourceFactory 接口

默认使用 @PropertySource 可以指定解析 properties 和 xml 配置文件,却不可以解析 yaml 配置文件,因为 spring 默认只有一个解析 properties 和 xml 文件的工厂类 DefaultPropertySourceFactory,没有解析 yaml 的工厂类,但是我们可以通过实现 PropertySourceFactory 接口自己写。

1. PropertySourceFactory 接口源码

发现其中只有一个方法 createPropertySource (),参考 DefaultPropertySourceFactory 类编写 yaml 解析工厂类。

package org.springframework.core.io.support;

import java.io.IOException;
import org.springframework.core.env.PropertySource;
import org.springframework.lang.Nullable;

public interface PropertySourceFactory {
    PropertySource<?> createPropertySource (@Nullable String var1, EncodedResource var2) throws IOException;
}
2. DefaultPropertySourceFactory 源码
package org.springframework.core.io.support;

import java.io.IOException;
import org.springframework.core.env.PropertySource;
import org.springframework.lang.Nullable;

public class DefaultPropertySourceFactory implements PropertySourceFactory {
    public DefaultPropertySourceFactory () {
    }

    public PropertySource<?> createPropertySource (@Nullable String name, EncodedResource resource) throws IOException {
        return name != null ? new ResourcePropertySource (name, resource) : new ResourcePropertySource (resource);
    }
}
3. 编写 yaml 解析工厂类
3.1 Maven 引入 yaml 工具包

spring 解析 yaml 依赖此包,不引入,用 maven-jar-plugin 打 jar 包后会出错

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>${snakeyaml.version}</version>
</dependency>
3.2 自定义工厂类 YamlPropertySourceFactory
package indi.tudan.devtools.spring.core.io.support;

import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;

import java.io.IOException;

/**
 * Yaml 配置文件读取工厂类
 *
 * @author wangtan
 * @date 2019-11-29 14:37:44
 * @since 1.0
 */
public class YamlPropertySourceFactory implements PropertySourceFactory {

    public YamlPropertySourceFactory () {
    }

    /**
     * yaml 文档解析方法
     *
     * @param name     配置项名称
     * @param resource 配置项资源
     * @return PropertySource<?>
     * @throws IOException IOException
     * @date 2019-11-29 14:45:00
     * @since 1.0
     */
    @Override
    public PropertySource<?> createPropertySource (@Nullable String name, EncodedResource resource) throws IOException {

        // 返回 yaml 属性资源
        return new YamlPropertySourceLoader ()
                .load (resource.getResource ().getFilename (), resource.getResource ())
                .get (0);
    }

}

yaml 配置文件

yaml:
  name: wangtan
  age: 26
  # 可以用 数组 或 List 接收
  pc: lenovo,dell
  # 可以用 数组 或 List 接收
  hobby:
    - lol
    - coding

编写配置映射类

在配置类中,指定解析 yaml 的自定义工厂类,factory = YamlPropertySourceFactory.class

package indi.tudan.devtools.common;

import indi.tudan.devtools.spring.core.io.support.YamlPropertySourceFactory;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * yaml 配置映射类
 *
 * @author wangtan
 * @date 2019-11-28 17:26:39
 * @since 1.0
 */
@Data
@Component
@PropertySource (
        name = "test.yml",
        value = {"classpath:config/test.yml"},
        ignoreResourceNotFound = false,
        encoding = "UTF-8",
        factory = YamlPropertySourceFactory.class
)
@ConfigurationProperties (prefix = "yaml")
public class TestYaml {

    private String name;

    private int age;

    private String [] pc;
    //private List<String> pc;

    private List<String> hobby;
    //private String [] hobby;

}

使用配置类

package indi.tudan.devtools.processor;

import indi.tudan.devtools.common.TestYaml;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * yaml 配置处理器
 *
 * @author wangtan
 * @date 2019-11-28 17:26:58
 * @since 1.0
 */
@Component
@EnableConfigurationProperties
public class YamlProcessor {

    @Autowired
    private TestYaml testYaml;

    /**
     * 执行
     *
     * @date 2019-11-28 17:28:05
     */
    public void start () {

        System.out.println (testYaml.toString ());
    }
}

控制台打印结果

TestYaml (name=wangtan, age=26, pc=[lenovo, dell], hobby=[lol, coding])