我们都知道,使用@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:
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
PropertySource
sfoo.bar
which comes from the blog.yaml
file