Spring Boot @PropertySource與yml文件一起使用

我們都知道,使用@PropertySource 的時候經常是類似於下面的用法。
 

@Component
@ConfigurationProperties(prefix = "netty-socket-io")
@PropertySource("classpath:server.properties")
@Getter
@Setter
public class ServerProperties {
    /**
     * socket端口
     */
    private Integer socketPort;

    /**
     * Ping消息間隔(毫秒)
     */
    private Integer pingInterval;

    /**
     * Ping消息超時時間(毫秒)
     */
    private Integer pingTimeout;

}

讀取的都是properties文件,但是當你自己自定義了yml文件,該怎麼用這種方法讀取呢?難不成把yml換成properties文件?如果文件特別大呢?不過作爲技術宅,有問題,還是應該解決一下問題。

Google上搜出了下面的文章,供參考。原文地址:https://mdeinum.github.io/2018-07-04-PropertySource-with-yaml-files/

By default the @PropertySource annotation isn’t usable with YAML files. This is also the standard answer given when asked on, for instance StackOverflow (even by me!).

But as of Spring 4.3 it’s possible to make it work. Spring 4.3 introduced the PropertySourceFactory interface. The PropertySourceFactory is a factory for a PropertySource. The default implementation used is the DefaultPropertySourceFactory, which creates ResourcePropertySource instances.

Writing a custom implementation requires implementing a single method, createPropertySource. The custom implementation needs to do 2 things:

  • Load the given resource into a java.util.Properties object
  • Create a PropertySource wrapping the loaded properties

To load a YAML file Spring provides the YamlPropertiesFactoryBean. This class will load 1 or more files and convert it into a java.util.Properties object. Spring provides a [PropertiesPropertySource] which wraps a java.util.Properties object. Finally the name of the PropertySource is either given or derived. The derived name is the resource description, as mentioned in the contract.

package biz.deinum.blog.yaml;

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

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.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;

public class YamlPropertySourceFactory implements PropertySourceFactory {

    @Override
    public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
        Properties propertiesFromYaml = loadYamlIntoProperties(resource);
        String sourceName = name != null ? name : resource.getResource().getFilename();
        return new PropertiesPropertySource(sourceName, propertiesFromYaml);
    }

    private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();
            return factory.getObject();
        } catch (IllegalStateException e) {
            // for ignoreResourceNotFound
            Throwable cause = e.getCause();
            if (cause instanceof FileNotFoundException)
                throw (FileNotFoundException) e.getCause();
            throw e;
        }
    }
}

NOTE: To load YAML it is required that SnakeYAML 1.18 or higher is on the classpath!

Next the YAML file, blog.yaml which we want to load:

foo:
  bar: baz

The @PropertySource annotation has a factory attribute. This is the attribute used to specify which PropertySourceFactory to use. Here we give it the value YamlPropertySourceFactory.class. The value attribute contains the name of the YAML resource to load.

package biz.deinum.blog.yaml;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;

@SpringBootApplication
@PropertySource(factory = YamlPropertySourceFactory.class, value = "classpath:blog.yaml")
public class YamlPropertysourceApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx =
                SpringApplication.run(YamlPropertysourceApplication.class, args);

        ConfigurableEnvironment env = ctx.getEnvironment();
        env.getPropertySources()
                .forEach(ps -> System.out.println(ps.getName() + " : " + ps.getClass()));

        System.out.println("Value of `foo.bar` = " + env.getProperty("foo.bar"));
    }
}

NOTE: Although this sample uses Spring Boot this isn’t required it works with plain Spring (version 4.3 or up) as well.

When running this application it will

  • Print the name and type of all available PropertySources
  • Get the value from foo.bar which comes from the blog.yaml file

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章