SpringBoot系列之@PropertySource读取yaml文件
SpringBoot系列之@PropertySource支持yaml文件读取
最近在做实验,想通过@PropertySource注解读取配置文件的属性,进行映射,习惯上用properties都是测试没问题的,偶然换成yaml文件,发现都读取不到属性值
因为yaml语法很简洁,比较喜欢写yaml配置文件,很显然,@PropertySource默认不支持yaml读取,我们改成@Value注解也是可以读取的,不过属性一堆的话,一个一个读取也是很繁琐的,通过网上找资料和自己实验验证,发现是可以实现对yaml支持
然后,为什么@PropertySource注解默认不支持?可以简单跟一下源码
@PropertySource源码:
根据注释,默认使用DefaultPropertySourceFactory类作为资源文件加载类
里面还是调用Spring框架底层的PropertiesLoaderUtils工具类进行读取的
PropertiesLoaderUtils.loadProperties
从源码可以看出也是支持xml文件读取的,能支持reader就获取reader对象,否则出件inputStream
load0方法是关键,这里加了同步锁
很重要的load0 方法抓取出来:
private void load0 (LineReader lr) throws IOException {
char[] convtBuf = new char[1024];
int limit;
// 当前key所在位置
int keyLen;
// 当前value所在位置
int valueStart;
char c;//读取的字符
boolean hasSep;
boolean precedingBackslash;//是否转义字符,eg:/n etc.
// 一行一行地读取
while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0;
valueStart = limit;
hasSep = false;
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
precedingBackslash = false;
//key的长度小于总的字符长度,那么就进入循环
while (keyLen < limit) {
c = lr.lineBuf[keyLen];
//need check if escaped.
if ((c == '=' || c == ':') && !precedingBackslash) {
valueStart = keyLen + 1;
hasSep = true;
break;
} else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
valueStart = keyLen + 1;
break;
}
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
keyLen++;
}
//value的起始位置小于总的字符长度,那么就进入该循环
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
//当前字符是否非空格类字符
if (c != ' ' && c != '\t' && c != '\f') {
if (!hasSep && (c == '=' || c == ':')) {
hasSep = true;
} else {
break;
}
}
valueStart++;
}
//读取key
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
//读取value
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
put(key, value);
}
}
ok,从源码可以看出,这个方法是一行一行地读取,然后根据冒号、等于号、空格等进行校验,经过一系列遍历之后获取key和value,而yaml语法是以缩进来辨别的,经过自己调试,这个方法也是不支持yaml文件的读取的,properties源码是比较多的,具体的Properties源码实现的可以参考博客:https://www.cnblogs.com/liuming1992/p/4360310.html,这篇博客写的比较详细
ok,然后给个例子来实现对yaml配置文件的读取
# 测试ConfigurationProperties
user:
userName: root
isAdmin: true
regTime: 2019/11/01
isOnline: 1
maps: {k1 : v1,k2: v2}
lists:
- list1
- list2
address:
tel: 15899988899
name: 上海市
模仿DefaultPropertySourceFactory写一个yaml资源文件读取的工厂类:
package com.example.springboot.properties.core.propertyResouceFactory;
import org.springframework.boot.env.YamlPropertySourceLoader;
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;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
/**
* <pre>
* YAML配置文件读取工厂类
* </pre>
* <p>
* <pre>
* @author nicky.ma
* 修改记录
* 修改后版本: 修改人: 修改日期: 2019/11/13 15:44 修改内容:
* </pre>
*/
public class YamlPropertyResourceFactory implements PropertySourceFactory {
/**
* Create a {@link PropertySource} that wraps the given resource.
*
* @param name the name of the property source
* @param encodedResource the resource (potentially encoded) to wrap
* @return the new {@link PropertySource} (never {@code null})
* @throws IOException if resource resolution failed
*/
@Override
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource encodedResource) throws IOException {
String resourceName = Optional.ofNullable(name).orElse(encodedResource.getResource().getFilename());
if (resourceName.endsWith(".yml") || resourceName.endsWith(".yaml")) {//yaml资源文件
List<PropertySource<?>> yamlSources = new YamlPropertySourceLoader().load(resourceName, encodedResource.getResource());
return yamlSources.get(0);
} else {//返回空的Properties
return new PropertiesPropertySource(resourceName, new Properties());
}
}
}
写个bean类进行属性映射,注意换一下factory参数,factory = YamlPropertyResourceFactory.class
package com.example.springboot.properties.bean;
import com.example.springboot.properties.core.propertyResouceFactory.CommPropertyResourceFactory;
import com.example.springboot.properties.core.propertyResouceFactory.YamlPropertyResourceFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* <pre>
*
* </pre>
*
* @author nicky
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 2019年11月03日 修改内容:
* </pre>
*/
@Component
@PropertySource(value = "classpath:user.yml",encoding = "utf-8",factory = YamlPropertyResourceFactory.class)
@ConfigurationProperties(prefix = "user")
public class User {
private String userName;
private boolean isAdmin;
private Date regTime;
private Long isOnline;
private Map<String,Object> maps;
private List<Object> lists;
private Address address;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", isAdmin=" + isAdmin +
", regTime=" + regTime +
", isOnline=" + isOnline +
", maps=" + maps +
", lists=" + lists +
", address=" + address +
'}';
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public boolean isAdmin() {
return isAdmin;
}
public void setAdmin(boolean admin) {
isAdmin = admin;
}
public Date getRegTime() {
return regTime;
}
public void setRegTime(Date regTime) {
this.regTime = regTime;
}
public Long getIsOnline() {
return isOnline;
}
public void setIsOnline(Long isOnline) {
this.isOnline = isOnline;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
package com.example.springboot.properties.bean;
/**
* <pre>
*
* </pre>
*
* @author nicky
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 2019年11月03日 修改内容:
* </pre>
*/
public class Address {
private String tel;
private String name;
@Override
public String toString() {
return "Address{" +
"tel='" + tel + '\'' +
", name='" + name + '\'' +
'}';
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
junit测试类代码:
package com.example.springboot.properties;
import com.example.springboot.properties.bean.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootPropertiesConfigApplicationTests {
@Autowired
User user;
@Test
public void testConfigurationProperties(){
System.out.println(user);
}
}
User{userName='root(15899988899)', isAdmin=false, regTime=Fri Nov 01 00:00:00 SGT 2019, isOnline=1, maps={k2=v2, k1=-30363940}, lists=[1f90e323-8a9c-4194-a31c-be9abbe9ce38, a869f68947faa92964d2a36ce86ee980], address=Address{tel='15899988899', name='上海浦东区'}}
如果既要支持原来的yaml,又要支持properties,就可以将propertyResourceFactory类进行改写一下:
package com.example.springboot.properties.core.propertyResouceFactory;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
/**
* <pre>
* 通用的资源文件读取工厂类
* </pre>
* <p>
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2019/11/25 10:35 修改内容:
* </pre>
*/
public class CommPropertyResourceFactory implements PropertySourceFactory {
/**
* Create a {@link PropertySource} that wraps the given resource.
*
* @param name the name of the property source
* @param resource the resource (potentially encoded) to wrap
* @return the new {@link PropertySource} (never {@code null})
* @throws IOException if resource resolution failed
*/
@Override
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
String resourceName = Optional.ofNullable(name).orElse(resource.getResource().getFilename());
if (resourceName.endsWith(".yml") || resourceName.endsWith(".yaml")) {
List<PropertySource<?>> yamlSources = new YamlPropertySourceLoader().load(resourceName, resource.getResource());
return yamlSources.get(0);
} else {
return new DefaultPropertySourceFactory().createPropertySource(name, resource);
}
}
}
调用的时候,要改一下factory参数
@PropertySource(value = "classpath:user.yml",encoding = "utf-8",factory = CommPropertyResourceFactory.class)
这个类就可以支持原来的properties文件,也可以支持yaml文件
User{userName='root(15899988899)', isAdmin=false, regTime=Fri Nov 01 00:00:00 SGT 2019, isOnline=1, maps={k2=v2, k1=-30363940}, lists=[1f90e323-8a9c-4194-a31c-be9abbe9ce38, a869f68947faa92964d2a36ce86ee980], address=Address{tel='15899988899', name='上海浦东区'}}
代码下载:github下载链接
SpringBoot系列之@PropertySource读取yaml文件的更多相关文章
- SpringBoot系列之@PropertySource用法简介
SpringBoot系列之@PropertySource用法简介 继上篇博客:SpringBoot系列之@Value和@ConfigurationProperties用法对比之后,本博客继续介绍一下@ ...
- Python读取Yaml文件
近期看到好多使用Yaml文件做为配置文件或者数据文件的工程,随即也研究了下,发现Yaml有几个优点:可读性好.和脚本语言的交互性好(确实非常好).使用实现语言的数据类型.有一个一致的数据模型.易于实现 ...
- 使用python读取yaml文件
在做APP测试时,通常需要把参数存到一个字典变量中,这时可以将参数写入yaml文件中,再读取出来. 新建yaml文件(android_caps.yaml),文件内容为: platformName: A ...
- java 读取 yaml 文件
做 java 项目用的最多的配置文件就是 properites 或者 xml, xml 确实是被用烂了,Struts, Spring, Hibernate(ssh) 无一不用到 xml.相比厚 ...
- python读取yaml文件,在unittest中使用
python读取yaml文件使用,有两种方式: 1.使用ddt读取 2,使用方法读取ddt的内容,在使用方法中进行调用 1.使用ddt读取 @ddt.ddt class loginTestPage(u ...
- Golang 入门系列(九) 如何读取YAML,JSON,INI等配置文件
实际项目中,读取相关的系统配置文件是很常见的事情.今天就来说一说,Golang 是如何读取YAML,JSON,INI等配置文件的. 1. json使用 JSON 应该比较熟悉,它是一种轻量级的数据交换 ...
- day11_单元测试_读取yaml文件中的用例,自动获取多个yaml文件内容执行生成报告
一.使用.yaml格式的文件直接可以存放字典类型数据,如下图,其中如果有-下一行有缩进代表这是个list,截图中是整体是一个list,其中有两部分,第二部分又包含另外一个list 二.单元测试:开发自 ...
- springBoot使用@Value标签读取*.properties文件的中文乱码问题
上次我碰到获取properties文件中的中文出现乱码问题. 查了下资料,原来properties默认的字符编码格式为asci码,所以我们要对字符编码进行转换成UTF-8格式 原先代码:@Proper ...
- Eclipse 创建和读取yaml文件
工具和用法: 1. eclipse插件包:org.dadacoalition.yedit_1.0.20.201509041456-RELEASE.jar 用法:将此jar包复制到eclipse-jee ...
随机推荐
- Python解释器安装及环境变量配置
python官网www.python.org 1.python3安装 1.1到官网找到电脑相应系统下载(下载路径越简单越好) 2.找需要下载的python版本 3. 手动添加环境变量 右键我的电脑-- ...
- sql语句对int类型进行模糊查询
重点:select * from course where cast(courseId as char) like '%118%'; 首先可以将int类型转换为string类型的值再进行模糊查询,用方 ...
- Django day03之表设计分析
models.py文件中创建表字段分析实例: 图书管理系统---> 书.作者.出版社作为基表 from django.db import models # Create your models ...
- 《Java算法》贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解. 贪心算法的经典案例: 跳跃游戏: 给定一个非负整 ...
- 流分析 Stream Analytics-实时数据流式处理,可处理来自数百万台 IoT 设备的数据
典型的物联网架构中,有实时数据分析的需求,在Azure中,流分析(stream analytics)就是这样的服务,它可以存在云中或者部署到边缘设备上. 流分析的基本概念: https://v.qq. ...
- 【AHOI 2013】差异
Problem Description 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \(\sum_{1\leqslant i&l ...
- 网易极客战记官方攻略-地牢-Kithgard 图书管理员
关卡连接: https://codecombat.163.com/play/level/kithgard-librarian 向友好的图书馆管理员求助! 简介 大多数关卡都有提示,在你卡关时挺有用. ...
- 使用GDAL/OGR读写矢量文件
感觉GIS中矢量相关内容还是挺庞杂的,并且由于版本迭代的关系,使用GDAL/OGR读写矢量的资料也有点不太一样.这里总结了一个读写矢量的示例,实现代码如下: #include <iostream ...
- HCTF_2018-Writeup【web题】
HCTF_2018-Writeup 赛题来自:BUUCTF By:Mirror王宇阳 WarmUp: 打开赛题的页面源码(F12) <!DOCTYPE html> <html lan ...
- 【代码审计】ESPCMSP8(易思企业建站管理系统)漏洞报告
0x00简介 项目名称:ESPCMS-P8(易思企业建站管理系统) 测试平台:Windwos 版本信息:P8.19082801稳定版 更新时间:2019-08-30 00:56:32 网站官网:htt ...