源码断点分析Spring的占位符(Placeholder)是怎么工作的

2023-11-15

项目中经常需要使用到占位符来满足多环境不同配置信息的需求,比如:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
       
    <bean id="myPropertyPlaceholderBean" class="com.example.demo1.PropertyPlaceholderBean">
        <property name="myPropertyName" value="${my.property.key}" />
    </bean>
    
</beans>

其中属性myPropertyName是带有’ ${}’ 符号,也就是占位符的变量,最终需要替换成具体的值,Spring会最终替换,那么它怎么做到的? 下面就通过打断点跟源码方式分析来分析说明。

还是以SpringBoot项目为例,在resources下定义结构如下:
在这里插入图片描述
以上结构是为了方便验证,随便定义的,大家可能有区别。
其中dev.properties定义两个key

test.env_var=123
my.property.key=justdoit

spring-bean1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myPropertyPlaceholderBean" class="com.example.demo1.PropertyPlaceholderBean">
        <property name="myPropertyName" value="${my.property.key}" />
    </bean>

</beans>

spring-application.xml如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder  location="classpath:properties/dev.properties" ignore-unresolvable="true" />
    <import resource="spring-bean1.xml"/>
</beans>

Spring boot启动类定义

@SpringBootApplication
@ImportResource({"classpath:spring-application.xml"})
public class ClientServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(ClientServerApplication.class, args);
	}
}

好了,下面开始分析整个过程…
首先从PropertySourcesPlaceholderConfigurer开始说,因为占位符默认就是由它来实现的。 进入其源码看到它是一个BeanFactoryPostProcessor 大家都知道,spring bean生命周期过程会执行所有BeanFactoryPostProcessor的postProcessBeanFactory方法,所以,肯定会进入到这个方法:
在这里插入图片描述
这里看到它尝试从两个地方去读取属性配置,一个是
以Environment为属性源的environmentProperties,另外一个就是通过loadProperties(Properties props)加载本地资源文件作为属性源的localProperties,我这个例子是第二种情况。

在这里插入图片描述
可以看到,已经加载到我上面配置的两个key-value
接着进入到下一步:
this.processProperties(beanFactory, (ConfigurablePropertyResolver)(new PropertySourcesPropertyResolver(this.propertySources)));

在这里插入图片描述
看到propertyResolver.setPlaceholderPrefix(this.placeholderPrefix)这些是设置缺省时,占位符的默认配置,即’${}’
其中注意一点,StringValueResolver valueResolver定义的是labmda表达式,后面会使用到。
接着下一步
在这里插入图片描述
上面这里是开始遍历所有的bean,替换其中包含占位符的bean的属性对象。
接着进入方法:
在这里插入图片描述遍历到我们自定义的bean,其中beanDefinition.getPropertyValues()是拿它的所有属性信息,如下图
在这里插入图片描述
遍历所有的属性,解析值,并且替换占位符
在这里插入图片描述
进入resolveValue方法,直接去到以下位置,因为属性类型是string嘛,所以直接跳到这里
在这里插入图片描述
可以看到我们bean中定义的占位符,接下来就是要替换它。接着看
在这里插入图片描述
发现此次是一个labmda表达式,就是上面提到的,所以执行回到上面的位置,
在这里插入图片描述
接着跟代码会进入到在这里插入图片描述
继续进入
parseStringValue
在这里插入图片描述
在这里插入图片描述
从propertySources里面去解析配置,疑问来了??这个对象什么时候放进去的,其实就是最开始提到的两个读取配置的地方,
一个是
以Environment为属性源的environmentProperties,另外一个就是通过loadProperties(Properties props)加载本地资源文件作为属性源的localProperties。
看以下代码就明白了,

if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
} else {
this.propertySources.addLast(localPropertySource);
}

解析完占位符得到值以后,出来回到resolveValue方法处,也就是很多if else的方法处,字符串位置
在这里插入图片描述
将属性值原本是${my.property.key}替换成justdoit

到此,对象PropertyPlaceholderBean定义的属性myPropertyName就被替换成具体的某个值了,这里也就是被替换成了 justdoit

总结:
基于Spring bean的生命周期,BeanFactoryPostProcessor执行方法postProcessBeanFactory,解析获取到属性源即environmentProperties以及localProperties两种,跟着解析占位符,然后得到具体的值,最后set进去替换占位符为具体的属性值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

源码断点分析Spring的占位符(Placeholder)是怎么工作的 的相关文章

随机推荐

  • 电容降压主要是用在直流稳压电源电路里

    https www cnblogs com jarvise p 4647029 html 基本原理 电容降压主要是用在直流稳压电源电路里 直流稳压电源电路的大致结构是 市电 变压 降压 整流 滤波 稳压 直流输出 变压 主要是降压 一般使用
  • 非线性微分跟踪器

    微分器描述 离散形式的非线性微分跟踪为 其中 h为采样周期 v k 为第k时刻的输入信号 为决定跟踪快慢的系数 fst 为最速控制综合函数 描述如下 仿真分析 微分器测试 输入信号v t sin2pit 采样周期h 0 001 150 扰动
  • 高性能本地存储设计

    本地存储常规架构 通用的云本地存储常规架构如下图所示 以MySQL数据库为例 它通过POSIX API与云主机内核交互 云主机内核包括一个标准文件系统和标准的块设备接口 云主机内核下面是云物理机内核 它自上而下由标准文件系统 标准块设备接口
  • STL之list(二)

    默认allocator为alloc 其具体使用版本请参照
  • HTML画布与SVG(Canvas vs. SVG)

    目录 画布 Canvas 什么是 Canvas 创建 Canvas 元素 通过 JavaScript 来绘制 理解坐标 更多 Canvas 实例 实例 线条 实例 圆形 实例 渐变 实例 图像 相关页面 SVG Scalable Vecto
  • 信号量的基本概念总结

    以下内容是摘抄博客 https blog csdn net fern girl article details 61197995 信号量的基本概念 一 首先 我们要知道信号量是什么 信号量的本质是数据操作锁 它本身不具有数据交换的功能 而是
  • FileSystemObject组件新建/读取/添加/修改/删除功能实例

  • MAC快捷键对照表

    Mac 键盘符号说明 Command Shift Caps Lock Option Control Return Enter Delete 向前删除键 Fn Delete 上箭头 下箭头 左箭头 右箭头 Page Up Fn Page Do
  • matlab kl散度,基于KL散度的面向对象遥感变化检测

    3 2 实验过程与结果 3 2 1 面向对象的遥感影像分割 利用ENVI软件的Segment Only Feature Extraction功能模块对实验数据进行面向对象分割操作 该方法采用的是Full Lambda Schedule分割算
  • 多益2018春招前端技术面试

    2018春招 多益网络内推 前端开发工程师 技术面问题 据我了解 从一月到三月份年 多益一共启动了至少三批春招招聘 从同学的反馈来看 一月份考验刚结束的那批春招通过率比较高 至于我个人 参加的是三月份上中旬的春招内推 可惜并没有通过 总体上
  • 虚拟机克隆后无法连接网络

    本文章转载自 Linux 无线图标莫名消失的解决方法 xin1889的博客 CSDN博客 今天我的也是的觉得再弄个虚拟机麻烦 索性就直接克隆了 然后连不上网 就连接原来的可以 连接百度也可以 但是唯独ping自己不行 然后不知道怎么回事 同
  • 智能指针和函数模板

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
  • c++学习笔记-#pragma once

    pragma 预处理宏的一般格式 pragma one one是参数 1 pragma message message 当编译器遇到这条指令时 它会在编译输出窗口中将message打印出来 常用于宏条件条件判断中使用 这样就知道自己的宏条件
  • 串口通信知识点总结

    串口通信小试牛刀 一 串口协议和RS 232标准 一 串口通讯协议 1 简介 2 串口通信的基本原理 二 RS232串口标准 1 简介 2 RS232串行接口的特点 3 RS232串行接口的电气特性 二 RS232电平与TTL电平 一 TT
  • Pytorch中多GPU并行计算教程

    如果不想看文字的 可以在我bilibili上看录制的视频教程 Pytorch多GPU使用教程 本教程所涉及的代码可自行在我的github上下载 https github com WZMIAOMIAO deep learning for im
  • layui添加菜单和动态操作tab

    layui添加菜单和动态操作tab 代码一 使用模板引擎渲染菜单 代码二修改版 代码一 使用模板引擎渲染菜单
  • JQ奇偶选择

    table tr even click function console log 选择奇数行 表示获取一个table 所有的索引为偶数的行 其中索引index 从0开始算起 0算偶数 table tr odd click function
  • Java运行时一个类是什么时候被加载的?

    A question a day get offer every day 未来的魔法师 一个类在什么时候开始被加载 Java虚拟机规范 中并没有进行强制约束 交给了虚拟机自己去自由实现 HotSpot虚拟机是按需加载 在需要用到该类的时候加
  • ThreadLocal源码分析,线程局部变量,内存泄漏?

    ThreadLocal作为线程局部变量 线程级的 单个线程内共享的 一般来说可以有两方面的用途 作为共享变量 在某些方法计算的结果 要共享到其他方法 在使用时 通过threadLocal set 设置值 通过threadLocal get
  • 源码断点分析Spring的占位符(Placeholder)是怎么工作的

    项目中经常需要使用到占位符来满足多环境不同配置信息的需求 比如