天天看點

springboot(四十)springboot中使@ProperySource适配yml檔案

作者:聰明的晚風zqw

@PropertySource加載指定的屬性檔案(*.properties)到 Spring 的 Environment 中。可以配合 @Value 和@ConfigurationProperties 使用:@PropertySource 和 @Value組合使用,可以将自定義屬性檔案中的屬性變量值注入到目前類的使用@Value注解的成員變量中;@PropertySource 和@ConfigurationProperties

組合使用,可以将屬性檔案與一個Java類綁定,将屬性檔案中的變量值注入到該Java類的成員變量中。

spring的@PropertySource注解隻支援引入properties檔案,引入yaml檔案會報錯,自定義PropertySourceFactory可以使之對yaml檔案做支援

跟蹤源碼發現:

DefaultPropertySourceFactory#createPropertySource中實作讀取配置檔案邏輯,如下:

public class DefaultPropertySourceFactory implements PropertySourceFactory {

	@Override
	public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
		return (name != null ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource));
	}
}           

ResourcePrepertySource構造器:

public ResourcePropertySource(String name, EncodedResource resource) throws IOException {
		super(name, PropertiesLoaderUtils.loadProperties(resource));
		this.resourceName = getNameForResource(resource.getResource());
	}           

PropertiesLoaderUtils#loadProperties(resource):

public static Properties loadProperties(EncodedResource resource) throws IOException {
		Properties props = new Properties();
		fillProperties(props, resource);
		return props;
	}           

能夠确定使用Properties 讀取的配置檔案,是以隻能支援.properties類型的檔案

為了對yaml檔案做支援,繼承DefaultPropertySourceFactory 重新實作讀取方法,判斷為yaml類型檔案自定義讀取邏輯,非yaml檔案繼續走之前的邏輯,如下:

package com.iscas.springboot.samples.property.resource;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;

import java.io.IOException;
import java.util.Properties;

/**
 * 相容配置,使得@PropertyResource注解也能支援yaml
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/6/21 21:24
 * @since jdk1.8
 */
public class MixPropertySourceFactory extends DefaultPropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = resource.getResource().getFilename();
        if (sourceName != null && (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml"))) {
            //将yaml檔案轉為properties
            return new PropertiesPropertySource(name, convert(resource));
        } else {
            return super.createPropertySource(name, resource);
        }
    }

    private Properties convert(EncodedResource encodedResource) {
        YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
        factory.setResources(encodedResource.getResource());
        factory.afterPropertiesSet();
        return factory.getObject();
    }
}           

測試:

定義一個yaml配置檔案test-property-source.yml:

person:
  zhangsan:
    age: 18           

使用:

package com.iscas.springboot.samples.property.resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 測試@PropertyResource
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2021/6/21 21:37
 * @since jdk1.8
 */
@RestController
@RequestMapping("/test/property/resource")
@PropertySource(name = "test-property-source.yml", value = "classpath:test-property-source.yml", factory = MixPropertySourceFactory.class)
public class TestPropertyResource  {

    @Value("${person.zhangsan.age}")
    private int age;

    @GetMapping
    public String testPropertyResource() {
        System.out.println("張三年齡:" + age);
        return "success";
    }
}           

通路這個接口,可以正常讀取到張三年齡

2021-06-21 22:07:07.801  INFO 20404 --- [nio-5678-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-06-21 22:07:07.801  INFO 20404 --- [nio-5678-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-06-21 22:07:07.802  INFO 20404 --- [nio-5678-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
張三年齡:18           

繼續閱讀