@PropertySource 支持 yml 文件

前言

项目开发中经常需要加载外部资源文件,@PropertySource给我们提供了极大的便利。但是@PropertySource目前不支持 yml 文件的解析,由于 yml 结构清晰等优点,使用频率也会越来越高。

源码解读

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {

    /**
     * Indicate the name of this property source. If omitted, a name will
     * be generated based on the description of the underlying resource.
     * @see org.springframework.core.env.PropertySource#getName()
     * @see org.springframework.core.io.Resource#getDescription()
     */
    String name() default "";

    /**
     * Indicate the resource location(s) of the properties file to be loaded.
     * 

Both traditional and XML-based properties file formats are supported * — for example, {@code "classpath:/com/myco/app.properties"} * or {@code "file:/path/to/file.xml"}. *

Resource location wildcards (e.g. **/*.properties) are not permitted; * each location must evaluate to exactly one {@code .properties} resource. *

${...} placeholders will be resolved against any/all property sources already * registered with the {@code Environment}. See {@linkplain PropertySource above} * for examples. *

Each location will be added to the enclosing {@code Environment} as its own * property source, and in the order declared. */ String[] value(); /** * Indicate if failure to find the a {@link #value() property resource} should be * ignored. *

{@code true} is appropriate if the properties file is completely optional. * Default is {@code false}. * @since 4.0 */ boolean ignoreResourceNotFound() default false; /** * A specific character encoding for the given resources, e.g. "UTF-8". * @since 4.3 */ String encoding() default ""; /** * Specify a custom {@link PropertySourceFactory}, if any. *

By default, a default factory for standard resource files will be used. * @since 4.3 * @see org.springframework.core.io.support.DefaultPropertySourceFactory * @see org.springframework.core.io.support.ResourcePropertySource */ Class factory() default PropertySourceFactory.class; }

注意 factory 这个属性,作为解析资源文件的工厂类,默认实现是 DefaultPropertySourceFactory

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));
    }
}

编码实现

我们只需要自定义一个工厂类 ResourceFactory,继承这个 default 工厂,重写 createPropertySource即可:

public class ResourceFactory extends DefaultPropertySourceFactory {

    @Override
    public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException {
        String sourceName = (name == null) ? resource.getResource().getFilename() : name;
        assert sourceName != null;
        if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            Properties properties = factory.getObject();
            assert properties != null;
            return new PropertiesPropertySource(sourceName, properties);
        }
        return super.createPropertySource(name, resource);
    }
}

新建测试文件 sso.yml:

sso:
  url: "http://www.baidu.com"
  name: sso-service

结合 @ConfigurationProperties实现 sso 配置类注入:

@Data
@Component
@ConfigurationProperties("sso")
@PropertySource(value = "classpath:sso.yml", factory = ResourceFactory.class)
public class Sso {

    private String url;
    private String name;

    @PostConstruct
    public void test(){
        System.out.println(this);
    }
}

test 方法作为测试输出当前信息:

Sso(url=http://www.baidu.com, name=sso-service)

你可能感兴趣的:(@PropertySource 支持 yml 文件)