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
相关文章:
SpringBoot之OriginTrackedPropertiesLoader类源码学习
源码解析 /*** 作用是从给定的资源(如文件或输入流)中加载 .properties 文件,* 并将属性键值对转换为带有来源信息(origin)的 OriginTrackedValue 对象。*/ public class OriginTrackedPropertiesLoader {private fin…...
51单片机 AT24C02(I2C总线)
存储器 随机存储 RAM 只读存储 ROM AT24C02芯片 是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息 存储材质:E2PROM 通讯接口:I2C总线 容量:256字节 I2C总线 一种通用的数据总线 两根通信线…...
Shell正则表达式与文本处理三剑客(grep、sed、awk)
一、正则表达式 Shell正则表达式分为两种: 基础正则表达式:BRE(basic regular express) 扩展正则表达式:ERE(extend regular express),扩展的表达式有、?、|和() 1.1 基本正则表…...
Docker Desktop 中安装 MySQL 并开启远程访问的详细教程
是在 Docker Desktop 中安装 MySQL 并开启远程访问的详细教程: 一、安装 MySQL 容器 拉取 MySQL 镜像: docker pull mysql:latest这将从 Docker Hub 上拉取最新版本的 MySQL 镜像。如果你想使用特定版本的 MySQL,可以将 latest 替换为具体…...
计算机网络 (39)TCP的运输连接管理
前言 TCP(传输控制协议)是一种面向连接的、可靠的传输协议,它在计算机网络中扮演着至关重要的角色。TCP的运输连接管理涉及连接建立、数据传送和连接释放三个阶段。 一、TCP的连接建立 TCP的连接建立采用三次握手机制,其过程如下&…...
麦田物语学习笔记:构建游戏的时间系统
基本流程 1.代码思路 (1)新建一个TimeManager.cs (2)创建枚举变量来表示四季,在TimeManager里需要的变量有: 游戏内的秒,分钟,小时,天,月,年;游戏内的季节;控制一个季节有多少个月;控制时间的暂停;计时器tikTime (3)在Settings里添加计时器的阈值,以及各个时间的进位 (4)初始化…...
Tauri教程-进阶篇-第二节 命令机制
“如果结果不如你所愿,就在尘埃落定前奋力一搏。”——《夏目友人帐》 “有些事不是看到了希望才去坚持,而是因为坚持才会看到希望。”——《十宗罪》 “维持现状意味着空耗你的努力和生命。”——纪伯伦 Tauri 技术教程 * 第五章 Tauri的进阶教程 第二节…...
candb++ windows11运行报错,找不到mfc140.dll
解决问题记录 mfc140.dll下载 注意:放置位置别搞错了...
提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息
网络和IP地址计算器 https://www.sojson.com/convert/subnetmask.html提供的 IP 地址 10.0.0.5 和子网掩码位 /26 来计算相关的网络信息。 子网掩码转换 子网掩码 /26 的含义二进制表示:/26 表示前 26 位是网络部分,剩下的 6 位是主机部分。对应的子网掩码为 255…...
vscode离线安装插件--终极解决方案
目录 离线安装插件安装方法 vscode连接远程服务器中的docker远程连接python jupyter开发 离线安装插件 使用vscode开发过程中,有一些内网服务器没法连接外网,造成安装插件不方便,网络上很多文章提供了很多方法,比较常见的一种是&…...
LabVIEW启动时Access Violation 0xC0000005错误
问题描述 在启动LabVIEW时,可能出现程序崩溃并提示以下错误:Error 0xC0000005 (Access Violation) Access Violation错误通常是由于权限不足、文件冲突或驱动问题引起的。以下是解决此问题的全面优化方案: 解决步骤 1. 以管理员身份运行…...
string(一)
一、了解string 可以看成是字符顺序表。 二、string遍历方式 1、下标[ ] 重载了[] for(int i 0; i < s.size(); i) {cout << s[i]; } 2、迭代器 auto it s.begin(); while(it ! s.end()) {cout << *it;it; } 3、范围for for(auto ch : s) {cout <&l…...
计算机网络 (41)文件传送协议
前言 一、文件传送协议(FTP) 概述: FTP(File Transfer Protocol)是互联网上使用得最广泛的文件传送协议。FTP提供交互式的访问,允许客户指明文件的类型与格式(如指明是否使用ASCII码࿰…...
C++ STL之容器介绍(vector、list、set、map)
1 STL基本概念 C有两大思想,面向对象和泛型编程。泛型编程指编写代码时不必指定具体的数据类型,而是使用模板来代替实际类型,这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C泛型编程的一个杰出例子。STL(Standard …...
redisson 连接 redis5报错 ERR wrong number of arguments for ‘auth‘ command
依赖版本 org.redisson:redisson-spring-boot-starter:3.25.2 现象 启动报错 org.redisson.client.RedisException: ERR wrong number of arguments for ‘auth’ command. channel: [xxx] command: (AUTH), params: (password masked) 原因 redis6以下版本认证参数不包含用…...
LeetCode:131. 分割回文串
跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:131. 分割回文串 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文串。返回 s 所…...
React-useState讲解
useState 让页面“动”起来 例如实现一个 click 计数功能,普通变量无法实现。即:修改普通变量无法触发组件的更新 rerender 通过 useState 即可实现。 state 是什么 State, A component’s memory —— 这个比喻非常好! props 父组件传…...
混币器是什么,波卡跨链交易平台
混币器是什么 混币器是一种加密货币工具,主要功能是将用户的加密货币与其他众多用户的加密货币混合在一起,打乱资金的流向和交易痕迹,使得加密货币的来源和去向难以追踪,从而增加交易的匿名性和隐私性。以下是对其工作流程和相关举例的介绍: 工作流程 用户首先将自己的加…...
【PHP】双方接口通信校验服务
请求方 使用 ApiAuthService::buildUrl($domain, [terminal > 1, ts > time()]); //http://域名/adminapi/login/platformLogin?signF7FE8A150DEC18BE8A71C5059742C81A&terminal1&ts1736904841接收方 $getParams $this->request->get();$validate ApiA…...
Web第一次作业
目录 题目 html代码 index login register css代码 base index login register 效果展示 index login register 题目 实现一个登录页面、实现一个注册页面;实现一个主页 - 登录页面:login.html - 注册页面:register.html - 主页…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
