SpringBoot之OriginTrackedPropertiesLoader类源码学习

源码解析

/*** 作用是从给定的资源(如文件或输入流)中加载 .properties 文件,* 并将属性键值对转换为带有来源信息(origin)的 OriginTrackedValue 对象。*/
public class OriginTrackedPropertiesLoader {private final Resource resource;/*** Create a new {@link OriginTrackedPropertiesLoader} instance.* @param resource the resource of the {@code .properties} data*/public OriginTrackedPropertiesLoader(Resource resource) {Assert.notNull(resource, "Resource must not be null");this.resource = resource;}/*** Load {@code .properties} data and return a map of {@code String} ->* {@link OriginTrackedValue}.* @return the loaded properties* @throws IOException on read error*/public Map<String, OriginTrackedValue> load() throws IOException {return load(true);}/*** 加载配置数据到一个Map中,根据指定的资源文件。* 如果expandLists为true,则将列表类型的配置项展开。** @param expandLists 是否展开列表类型的配置项* @return 包含配置数据的Map,键为配置项名称,值为配置项的值和来源信息* @throws IOException 如果读取资源文件时发生错误*/Map<String, OriginTrackedValue> load(boolean expandLists) throws IOException {//创建CharacterReader对象,用于逐行读取资源文件内容。try (CharacterReader reader = new CharacterReader(this.resource)) {//初始化结果MapMap<String, OriginTrackedValue> result = new LinkedHashMap<>();//初始化字符串缓冲区StringBuilder buffer = new StringBuilder();//循环读取逐行资源文件内容,直到文件末尾while (reader.read()) {//读取配置项的键名,并去除前后空格String key = loadKey(buffer, reader).trim();//如果配置项是列表类型且需要展开列表,则处理列表配置项if (expandLists && key.endsWith("[]")) {//去除列表配置项的"[]"后缀key = key.substring(0, key.length() - 2);//初始化列表索引int index = 0;//循环读取列表中的每个配置项do {//读取配置项的值OriginTrackedValue value = loadValue(buffer, reader, true);//将配置项添加到结果Map中,键名格式为key[index]put(result, key + "[" + (index++) + "]", value);//如果当前行不是行尾,则继续读取if (!reader.isEndOfLine()) {reader.read();}} while (!reader.isEndOfLine());}else {//读取非列表配置项的值OriginTrackedValue value = loadValue(buffer, reader, false);//将配置项添加到结果Map中put(result, key, value);}}//返回包含所有配置项的Mapreturn result;}}/*** 从输入中加载属性键* 该方法负责读取输入直到遇到属性分隔符或行尾,同时忽略前导和尾随的空白字符** @param buffer 用于存储读取的键的字符串构建器* @param reader 提供输入字符的字符阅读器* @return 返回读取的属性键的字符串表示* @throws IOException 如果读取过程中发生I/O错误*/private String loadKey(StringBuilder buffer, CharacterReader reader) throws IOException {// 清空缓冲区以准备读取新的键buffer.setLength(0);// 初始化前一个字符是否为空白字符的标志boolean previousWhitespace = false;// 循环读取直到行尾while (!reader.isEndOfLine()) {// 如果遇到属性分隔符,读取下一个字符并返回当前缓冲区的内容if (reader.isPropertyDelimiter()) {reader.read();return buffer.toString();}// 如果当前字符不是空白字符,但前一个字符是空白字符,则返回当前缓冲区的内容if (!reader.isWhiteSpace() && previousWhitespace) {return buffer.toString();}// 更新前一个字符是否为空白字符的标志previousWhitespace = reader.isWhiteSpace();// 将当前字符追加到缓冲区中buffer.append(reader.getCharacter());// 读取下一个字符reader.read();}// 如果到达行尾,返回当前缓冲区的内容return buffer.toString();}/*** 从输入中加载一行值,可以选择性地在列表分隔符处分割** @param buffer 缓存区,用于存储从输入中读取的值* @param reader 字符读取器,用于从输入源读取字符* @param splitLists 指示是否应在遇到列表分隔符时分割的布尔值* @return 返回一个包含值及其来源信息的OriginTrackedValue对象* @throws IOException 如果在读取过程中发生I/O错误*/private OriginTrackedValue loadValue(StringBuilder buffer, CharacterReader reader, boolean splitLists)throws IOException {// 清空缓冲区以准备读取新的值buffer.setLength(0);// 跳过行首的空白字符,直到遇到非空白字符或行尾while (reader.isWhiteSpace() && !reader.isEndOfLine()) {reader.read();}// 记录当前读取位置,用于后续创建Origin对象Location location = reader.getLocation();// 读取字符直到行尾或(如果splitLists为真)遇到列表分隔符while (!reader.isEndOfLine() && !(splitLists && reader.isListDelimiter())) {buffer.append(reader.getCharacter());reader.read();}// 创建一个表示值来源的Origin对象Origin origin = new TextResourceOrigin(this.resource, location);// 使用缓冲区中的字符串和其来源信息创建并返回一个OriginTrackedValue对象return OriginTrackedValue.of(buffer.toString(), origin);}/*** Reads characters from the source resource, taking care of skipping comments,* handling multi-line values and tracking {@code '\'} escapes.* 用于逐字符读取文件内容,处理注释、转义字符、多行值等特殊情况。* 提供了多种辅助方法来跳过空白字符、处理注释、读取转义字符等。*/private static class CharacterReader implements Closeable{//省略......}}

案例

test-properties.properties配置文件

   # foo
blah   =   hello world
bar   foo=baz
hello   world
proper\\ty=test
foo
bat = a\\
bling = a=b#commented-property=test
test=properties
test-unicode=properties\u0026test# comment ending \
test\=property=helloworld
test-colon-separator: my-property
test-tab-property=foo\tbar
test-return-property=foo\rbar
test-newline-property=foo\nbar
test-form-feed-property=foo\fbar
test-whitespace-property   =   foo   bar
test-multiline= a\b\\\c
foods[]=Apple,\
Orange,\
Strawberry,\
Mango
languages[perl]=Elite
languages[python]=Elite
language[pascal]=Lame
test-multiline-immediate=\
foo
!commented-two=bang\
test-bang-property=foo!
another=bar
test-property-value-comment=foo \
!bar #foo
test-multiline-immediate-bang=\
!foo#test ISO 8859-1
test-iso8859-1-chars=����������test-with-trailing-space= trailing 
	private ClassPathResource resource;private Map<String, OriginTrackedValue> properties;@Testvoid compareToJavaProperties() throws Exception {String path = "test-properties.properties";this.resource = new ClassPathResource(path, getClass());this.properties = new OriginTrackedPropertiesLoader(this.resource).load();Properties java = PropertiesLoaderUtils.loadProperties(this.resource);Properties ours = new Properties();new OriginTrackedPropertiesLoader(this.resource).load(false).forEach((k, v) -> System.out.println(k+":"+v.getValue()));}

运行结果

blah:hello world
bar:foo=baz
hello:world
proper\ty:test
foo:
bat:a\
bling:a=b
test:properties
test-unicode:properties&test
test=property:helloworld
test-colon-separator:my-property
test-tab-property:foo	bar
bar
test-newline-property:foo
bar
test-form-feed-property:foobar
test-whitespace-property:foo   bar
test-multiline:ab\c
foods[]:Apple,Orange,Strawberry,Mango
languages[perl]:Elite
languages[python]:Elite
language[pascal]:Lame
test-multiline-immediate:foo
test-bang-property:foo!
another:bar
test-property-value-comment:foo !bar #foo
test-multiline-immediate-bang:!foo
test-iso8859-1-chars:����������
test-with-trailing-space:trailing 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/892682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx 实现 正向代理、反向代理 、SSL(证书配置)、负载均衡 、虚拟域名 ,使用其他中间件监控

我们可以详细地配置 Nginx 来实现正向代理、反向代理、SSL、负载均衡和虚拟域名。同时&#xff0c;我会介绍如何使用一些中间件来监控 Nginx 的状态和性能。 1. 安装 Nginx 如果你还没有安装 Nginx&#xff0c;可以通过以下命令进行安装&#xff08;以 Ubuntu 为例&#xff0…

React性能优化: 使用React.lazy与Suspense提高加载效率

## 1. React.lazy与Suspense简介 在开发React应用程序时&#xff0c;我们经常会遇到需要加载大型组件或者数据的情况。为了提高页面加载的效率&#xff0c;React引入了React.lazy和Suspense这两个特性。 什么是React.lazy&#xff1f; 是React 16.6版本引入的新特性&#xff0c…

开发人员学习书籍推荐(C#、Python方向)

作为一名开发人员&#xff0c;持续学习和提升自己的技术水平是至关重要的。如今&#xff0c;技术不断更新换代&#xff0c;新的开发框架、语言和工具层出不穷。对于刚入行的开发者或希望深入某一领域的工程师来说&#xff0c;选对书籍是学习的捷径之一。本篇文章将推荐一些经典…

Golang笔记——Interface类型

大家好&#xff0c;这里是Good Note&#xff0c;关注 公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍Golang的interface数据结构类型&#xff0c;包括基本实现和使用等。 文章目录 Go 语言中的 interface 详解接口定义实现接口空接口 interface{}示…

轨迹优化 | 基于贝塞尔曲线的无约束路径平滑与粗轨迹生成(附ROS C++/Python仿真)

目录 0 专栏介绍1 从路径到轨迹2 基于贝塞尔曲线的粗轨迹生成2.1 路径关键点提取2.2 路径点航向角计算2.3 贝塞尔曲线轨迹生成 3 算法仿真3.1 ROS C仿真3.2 Python仿真 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划…

理解STC15F2K60S2单片机的最小电路

一、STC15F2K60S2与51单片机的区别 STC15F2K60S2和51单片机虽然都基于8051内核&#xff0c;但在多个方面存在显著区别&#xff1a; 1. CPU性能&#xff1a; - STC15F2K60S2&#xff1a;采用增强型8051 CPU&#xff0c;1T单时钟/机器周期&#xff0c;速度比普通8051快8-12倍…

微信小程序获取当前页面路径,登录成功后重定向回原页面

&#x1f935; 作者&#xff1a;coderYYY &#x1f9d1; 个人简介&#xff1a;前端程序媛&#xff0c;目前主攻web前端&#xff0c;后端辅助&#xff0c;其他技术知识也会偶尔分享&#x1f340;欢迎和我一起交流&#xff01;&#x1f680;&#xff08;评论和私信一般会回&#…

Linux学习指南与资料分享

Linux学习资料 Linux学习资料 Linux学习资料 基础入门 了解 Linux 基础概念&#xff1a; Linux 是开源类 Unix 操作系统&#xff0c;由内核、Shell 和应用程序组成。学习时要了解其开源、稳定、安全等特性&#xff0c;以及多用户、多任务的特点。 选择并安装 Linux 发行版…

VSCode 搜索 搜不到

VSCode 搜索 搜不到 今天打开一个新的工作目录之后 ctrl P 搜文件 搜不到 经观察后发现 当我搜索时候&#xff0c; 右侧搜索按钮有一个时钟标识&#xff0c;疑似 搜索的范围 是最近打开内容。 经过和全局搜索的编辑器对比设置后发现&#xff0c;把设置中 下图中 选项去掉勾选…

软件测试 —— Selenium常用函数

软件测试 —— Selenium常用函数 操作测试对象点击/提交对象 click()模拟按键输入 send_keys("")清除文本内容 clear() 模拟用户键盘行为 Keys包示例用法 获取文本信息 textget_attribute("属性名称") 获取当前页面标题 title获取当前页面的 url current_u…

【9.1】Golang后端开发系列--Gin快速入门指南

文章目录 一、引言 &#x1f31f;二、Gin 框架概述 &#x1f4d6;&#xff08;一&#xff09;什么是 Gin&#xff08;二&#xff09;为什么选择 Gin 三、安装 Gin 框架 &#x1f4e6;&#xff08;一&#xff09;安装 Go 语言环境&#xff08;二&#xff09;使用 Go Modules 安装…

Vue 学习之旅:核心技术学习总结与实战案例分享(vue指令下+计算属性+侦听器)

Vue 学习之旅&#xff1a;核心技术学习总结与实战案例分享 文章目录 Vue 学习之旅&#xff1a;核心技术学习总结与实战案例分享一、指令补充&#xff08;一&#xff09;指令修饰符&#xff08;二&#xff09;v-bind 对样式操作的增强&#xff08;三&#xff09;v-model 应用于其…

OpenCV相机标定与3D重建(55)通用解决 PnP 问题函数solvePnPGeneric()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 根据3D-2D点对应关系找到物体的姿态。 cv::solvePnPGeneric 是 OpenCV 中一个更为通用的函数&#xff0c;用于解决 PnP 问题。它能够返回多个可能…

UE5 打包项目

UE5 打包项目 flyfish 通过 “文件”->“打开项目”&#xff0c;然后在弹出的对话框中选择项目文件&#xff08;通常是以.uproject为后缀的文件&#xff09; 选择目标平台&#xff1a; 在 UE5 主界面中&#xff0c;找到 “平台”&#xff08;Platforms&#xff09;。根据…

1. Doris分布式环境搭建

一. 环境准备 本次测试集群采用3台机器hadoop1、hadoop2、hadoop3, Frontend和Backend部署在同一台机器上&#xff0c;Frontend部署3台组成高可用&#xff0c;Backend部署3个节点&#xff0c;组成3副本存储。 主机IP操作系统FrontendBackendhadoop1192.168.47.128Centos7Foll…

win10电脑 定时关机

win10电脑 定时关机 https://weibo.com/ttarticle/p/show?id2309405110707766296723 二、使用任务计划程序设置定时关机打开任务计划程序&#xff1a; 按下“Win S”组合键&#xff0c;打开搜索框。 在搜索框中输入“任务计划程序”&#xff0c;然后点击搜索结果中的“任务…

Markdown中甘特图的使用

Markdown中甘特图的使用 1. 前言2. 语法详解2.1 甘特图语法 3. 使用场景及实例4. 小结5. 其他文章快来试试吧&#x1f58a;️ Markdown中甘特图的使用 &#x1f448;点击这里也可查看 1. 前言 Markdown 的原生语法不支持绘制图形&#xff0c;但通过扩展模块&#xff0c;我们可…

python bs4 selenium 查找a href=javascript:();的实际点击事件和url

在使用 BeautifulSoup 和 Selenium 时&#xff0c;处理 href"javascript:;" 的链接需要一些额外的步骤&#xff0c;因为这些链接不直接指向一个 URL&#xff0c;而是通过 JavaScript 代码来执行某些操作。这可能包括导航到另一个页面、触发模态窗口、显示/隐藏内容等…

day07_Spark SQL

文章目录 day07_Spark SQL课程笔记一、今日课程内容二、Spark SQL函数定义&#xff08;掌握&#xff09;1、窗口函数2、自定义函数背景2.1 回顾函数分类标准:SQL最开始是_内置函数&自定义函数_两种 2.2 自定义函数背景 3、Spark原生自定义UDF函数3.1 自定义函数流程&#x…

Laravel 中 Cache::remember 的基本用途

在 Laravel 中&#xff0c;Cache::remember 方法用于缓存数据&#xff0c;以提高应用程序的性能。当需要从数据库或其他较慢的数据源中检索数据时&#xff0c;可以使用 Cache::remember 来检查请求的数据是否已经被缓存。如果数据已缓存&#xff0c;则直接从缓存中读取&#xf…