记一次SpringBoot2.x的@ImportResource和@PropertySource的坑
众所周知,SpringBoot提倡的是无配置文件,也就摒弃了以前用Spring时繁重的.xml配置文件,取而代之的使用SpringBoot特有的@Configuration注解的JavaConfig配置类。配置方式和XML配置方式几乎一一对应,少有区别。
那么当我们需要在SpringBoot中,需要使用XML配置文件,或者需要使用额外的.properties, .yml文件时,我们需要怎么做?
这时候就想到了几种方式:@ImportResource, @PropertySource
@ImportResource 是用于导入外部的.xml文件
@PropertySource 是用于导入变量类型的配置文件如.properties .yml
如果你用@ImportResource(locations = “xxx.yml”),通常情况你会得到这样的报错,
Caused by: org.xml.sax.SAXParseExcepton; lineNumber: 1; columnNumber: 1; 前言中不允许有内容 网上有大量关于这种错误的说法,但是绝大部分都是说你的文件编码格式有问题,需要转换。我在试过大量的方法后,还是不行,同时我也看到很多解决帖的下方留言,大多数都是留言不行,解决不了,我高度怀疑那些没质量的解决帖都是互相抄袭的。但是有一种方法我没有试,就是用notePad方式打开文件,然后保存为 UTF-8 with no BOM 的方式。
在尝试了很多次之后,我都无法通过@ImportResource的方式来导入外部.yml .properties配置文件,我也没有细心去查阅相关的源码,因此我转而关注@PropertySource来帮助我解决问题。
在使用@PropertySource的时候又发现了一个问题,它能正常帮助我导入.properties文件,我也能通过@ConfigurationProperties和@Value来得到配置文件中的相应变量值,但是它不能正确解读.yml文件。我想对于SpringBoot的常年开发者来说,早就已经把习惯改为用YML语言来书写配置文件,要换回使用properties虽然不麻烦,也有转换工具帮助,但是就不能有一种方法解决这个问题吗?
可喜可贺的是,@PropertySource里面有一个属性叫factory,默认实现类是DefaultPropertySourceFactory,这个factory的作用是解析配置文件,因此简单翻阅了DefaultPropertySourceFactory的源码,发现它对yml的支持非常鸡肋,默认是只能解析.properties文件。因此我对其做了扩展,让其在解析配置文件的时候,判断配置文件是.properties还是.yml,然后走相应的解析逻辑。
代码语言:javascript复制/**
* 该类是扩展{@link org.springframework.core.io.support.DefaultPropertySourceFactory}的,
* 用于{@link org.springframework.context.annotation.PropertySource}的factory属性。
*
* @PropertySource的facotroy属性,默认是使用 DefaultPropertySourceFactory 实现。该实现只能解析.properties配置文件,
* 因此.yml文件无法解析。
*
*/
public class YmlPropertiesFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource)
throws IOException {
String sourceName = Optional.ofNullable(name).orElse(resource.getResource().getFilename());
if (!resource.getResource().exists()) {
// return an empty Properties
return new PropertiesPropertySource(sourceName, new Properties());
} else if (sourceName.endsWith(".yml") || sourceName.endsWith(".yaml")) {
Properties propertiesFromYaml = loadYaml(resource);
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
} else {
return super.createPropertySource(name, resource);
}
}
/**
* load yaml file to properties
*
* @param resource
* @return
* @throws IOException
*/
private Properties loadYaml(EncodedResource resource) throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
}
}
代码语言:javascript复制@PropertySource(value = {"classpath:dy.yml"}, ignoreResourceNotFound = true, factory = YmlPropertiesFactory.class)
好了,现在你就能正常解析YML文件
小结:
(1) 如果你要导入外部XML文件,用@ImportResource (2) 如果你要导入的是.properties .yml这样的配置文件,用@PropertySource