springboot配置注入增强(二)属性注入的原理
一 原理
1 配置的存储
springboot在启动的时候会后构建一个org.springframework.core.env.Environment类型的对象,这个对象就是用于存储配置,如图springboot会在启动的最开始创建一个Environment对象



这个webApplicationType的枚举是在new SpringApplication()时候指定的


- 如果org.springframework.web.reactive.DispatcherHandler存在并且可加载(他本身或其依赖项之一不存在或无法加载),并且org.springframework.web.servlet.DispatcherServlet不存在或不可加载,并且org.glassfish.jersey.servlet.ServletContainer不存在或不可加载,那么就会使用WebApplicationType.REACTIVE,构建ApplicationReactiveWebEnvironment类型的Environment对象,即Spring WebFlux框架
- 如果javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext中任何一个不存在或不可加载,那么就会使用WebApplicationType.NONE,构建ApplicationEnvironment类型的Environment对象,即普通spring非web框架
- 否则就会使用WebApplicationType.SERVLET,构建ApplicationServletEnvironment类型的Environment对象,即Servlet也就是spring mvc框架
我们以常用的spring mvc为例,先看下ApplicationServletEnvironment类的数据结构(都大同小异)

本质是一个PropertyResolver接口,核心是能提供一个根据配置中某个属性的key获取对应属性值的方法和跟据某个规则解析属性值的方法,他所有的子类都是在对其做一些扩张,让其使用更方便,比如ConfigurableEnvironment增加的MutablePropertySources getPropertySources()方法,就是为了能获取到全部的配置内容

其实springboot的这三种Environment都是StandardEnvironment的子类,而StandardEnvironment的父类AbstractEnvironment使用了MutablePropertySources作为数据源集合的类型,当然它也是根据其实现接口ConfigurableEnvironment中的MutablePropertySources getPropertySources()方法来确定数据源集合的类型。

可以看出来这个类对比原始的PropertyResolver接口多一个数据源集合,springboot的配置原理简单来说就是将不同来源的配置组装成不同数据源类型的数据源对象,然后放到MutablePropertySources中根据名称和数据源对象进行key-value存储,使用的时候遍历MutablePropertySources中所有的数据源的value,从中找到第一个符合条件的值,找到之后再进行解析,比如${xxxx}这种。这个使用的逻辑即PropertyResolver接口的全部实现是由PropertySourcesPropertyResolver对象代理的(在AbstractEnvironment的构造方法中会new一个PropertySourcesPropertyResolver对象)
MutablePropertySources中有一个List<PropertySource<?>> propertySourceList成员变量,这个就是上面说的数据源集合

PropertySource就是具体的配置了,其实也就两个变量,name:数据源名称,source:具体的数据源。这个实现类有很多,我们也可以自己定义,比如自己创建一个类用做source,然后实现PropertySource那几个根据source查询值的方法


2 配置的来源
其实这个配置的来源可以任何时候添加到Environment对象中,只不过如果想让springboot在启动过程中加载bean时使用到我们的数据源,我们应该在PropertySourcesPlaceholderConfigurer的postProcessBeanFactory()方法执行前加进Environment中,低版本的springboot用的是PropertyPlaceholderConfigurer,不过这个早就已经弃用了所以也就不用管他了,下面我们介绍下PropertySourcesPlaceholderConfigurer

可以看到他是一个BeanFactoryPostProcessor实现类,这个类会在启动的refresh阶段执行postProcessBeanFactory()方法

可以看到,这里会新建一个数据源集合,并且把environment和localProperties加进去,这个localProperties就是我们手动构建PropertySourcesPlaceholderConfigurer时指定的配置文件路径
@Beanpublic static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();configurer.setLocation(new ClassPathResource("config.properties"));return configurer;}
之后会将这个数据源集合封装为一个StringValueResolver用于解析属性


可以看到这个先被用于解析bean的属性如这种的${xx},其实我感觉这个也是为了兼容老代码,毕竟最早的spring也只有在配置文件里注入的这种方式
<bean id="cacheService" class="my.user.UserImpl"><property name="name" value="${user.123.name}"/></bean>
然后可以看到执行了beanFactoryToProcess.addEmbeddedValueResolver(valueResolver)方法,这个方法只是将这个valueResolver解析器存了起来,现在还没用。

会等到解析@value时候在AutowiredAnnotationBeanPostProcessor用到,下面介绍几个系统配置的常用的数据源
2.1 系统的环境变量和java启动时的启动参数
StandardEnvironment在初始化时会由父类执行StandardEnvironment的customizePropertySources方法创建两个数据源放到数据源集合,这两个数据源我们也很熟悉,就是系统的环境变量和java启动时的启动参数即System.getenv()和System.getProperties()

2.2 application.yml
旧版本是由ConfigFileApplicationListener作为启动监听器,在监听到ApplicationEnvironmentPreparedEvent事件也就是创建完Environment后会发的一个事件中加载的

可以看到他也实现了EnvironmentPostProcessor接口,并把自身和其他spring.factories文件中配置的org.springframework.boot.env.EnvironmentPostProcessor=xxxx,合并一起执行对应的postProcessEnvironment()方法,而他本身的postProcessEnvironment方法会加载application.yml文件
新版本是用ConfigDataEnvironmentPostProcessor加载的,同时ConfigFileApplicationListener被废弃了,改为由EnvironmentPostProcessorApplicationListener来执行EnvironmentPostProcessor的方法,职责单一更清晰了些



2.3 PropertySources/PropertySource
PropertySources其实就是PropertySource的集合,是由ConfigurationClassPostProcessor将PropertySource路径的配置文件内容添加到environment中


可以看到这个路径甚至还支持${xxx}这种动态路径(environment.resolveRequiredPlaceholders会将${xxx}从environment对象中获取真正的值),然后将多个location解析后的propertySource组合起来形成一个CompositePropertySource对象

3 配置的使用
3.1 BeanDefinition 的属性注入
上面介绍过,通常就是对BeanDefinition的propertyValues进行解析,在PropertySourcesPlaceholderConfigurer里
<bean id="cacheService" class="my.user.UserImpl"><property name="name" value="${user.123.name}"/></bean>
3.2 @Value
上面也介绍过在AutowiredAnnotationBeanPostProcessor会进行解析
@Value("${user.123.name}")private String user123Name;
3.3 @ConfigurationProperties
@Data
@Component
@ConfigurationProperties(prefix = "user.123")
public class UserConfiguration {/*** 姓名*/private String name;/*** 性别*/private String sex;
}
他是由ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitialization(Object bean, String beanName)来进行绑定的



可以看到实际上执行的是Binder的bind()方法,这个方法可以将以某个相同前缀的属性绑定到对应对象的属性上,主要关注Binder构造器的前两个参数Iterable<ConfigurationPropertySource> sources, PlaceholdersResolver placeholdersResolver,可以看到都是用propertySources作为数据源来进行查找和解析的,而这个propertySources是ConfigurationPropertiesBinder.register(registry)方法中调用ConfigurationPropertiesBinder.Factory#create()方法中生成的





可以看到如果只有一个PropertySourcesPlaceholderConfigurer类型的bean时,这个数据源就是我们上面说的那个和3.1和3.2所用的一样的数据源PropertySourcesPlaceholderConfigurer的appliedPropertySources。否则就会用Environment作为数据源


3.4 environment
这个就简单了,直接从environment对象取即可
- environment.getProperty("user.123.name")
- environment.resolvePlaceholders("${user.123.name}")
- environment.resolveRequiredPlaceholders("${user.123.name}") 如果解析不到会报错
相关文章:
springboot配置注入增强(二)属性注入的原理
一 原理 1 配置的存储 springboot在启动的时候会后构建一个org.springframework.core.env.Environment类型的对象,这个对象就是用于存储配置,如图springboot会在启动的最开始创建一个Environment对象 这个webApplicationType的枚举是在new SpringAppli…...
Android 使用Camera1实现相机预览、拍照、录像
1. 前言 本文介绍如何从零开始,在Android中实现Camera1的接入,并在文末提供Camera1Manager工具类,可以用于快速接入Camera1。 Android Camera1 API虽然已经被Google废弃,但有些场景下不得不使用。 并且Camera1返回的帧数据是NV21…...
2024字节跳动校招面试真题汇总及其解答(四)
12.Java的类加载机制 Java的类加载机制是指将描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。 类的加载过程分为以下五个阶段: 加载:将Class文件从磁盘读入内存,并…...
网页的快捷方式打开自动全屏--Chrome、Firefox 浏览器相关设置
Firefox 的全屏方式与 Chrome 不同,Chrome 自带全屏模式以及APP模式,通过简单的参数即可设置,而Firefox暂时么有这个功能,Firefox 的全屏功能可以通过全屏插件实现。 全屏模式下,按 F11 不会退出全屏,鼠标…...
LabVIEW使用ModbusTCP协议构建分布式测量系统
LabVIEW使用ModbusTCP协议构建分布式测量系统 分布式测量系统主要用于监控远程物体。这种系统允许对系统用户获得的数据进行全面的数据收集、处理、存储和组织访问。它们可能包括许多不同类型的传感器。 在任何具有互联网接入的个人计算机上运行的软件都会发送来自传感器的测…...
unity学习第1天
本身也具有一些unity知识,包括Eidtor界面使用、Shader效果实现、性能分析,但对C#、游戏逻辑不太清楚,这次想从开发者角度理解游戏,提高C#编程,从简单的unity游戏理解游戏逻辑,更好的为工作服务。 unity201…...
Spring Boot实现对文件进行压缩下载
在Web应用中,文件下载功能是一个常见的需求,特别是当你需要提供用户下载各种类型的文件时。本文将演示如何使用Spring Boot框架来实现一个简单而强大的文件下载功能。我们将创建一个RESTful API,通过该API,用户可以下载问价为ZIP压…...
Mac专用投屏工具AirServer 7 .27 for Mac中文免费激活版
AirServer 7 .27 for Mac中文免费激活版是一款Mac专用投屏工具,能够通过本地网络将音频、照片、视频以及支持AirPlay功能的第三方App,从 iOS 设备无线传送到 Mac 电脑的屏幕上,把Mac变成一个AirPlay终端的实用工具。 目前最新的AirServer 7.2…...
LabVIEW使用巴特沃兹低通滤波器过滤噪声
LabVIEW使用巴特沃兹低通滤波器过滤噪声 设备采集到的数据往往都有噪声,有时候这些数据要做判断使用,如果不处理往往会影响最终的结果。可以使用动态平滑,或者中值滤波等方法。这里介绍使用巴特沃斯低通滤波,也是非常方便的。 下…...
【Realtek sdk-3.4.14b】RTL8197FH-VG和RTL8812F自适应认证失败问题分析及修改
WiFi自适应认证介绍 WiFi 自适应可以理解为针对WiFi的产品,当有外部干扰信号通过,WiFi产品自动停止发出信号一段时间,以达到避让的目的。 问题描述 2.4G和5G WiFi自适应认证失败,信道停止发送信号时间过长,没有在规定时间内停止发包 2.4G截图 问题分析 根据实验室描述可以…...
SpringBoot 的版本、打包、Maven
一、SpringBoot 结构、集成 1.1、集成组件 Spring Core:Spring的核心组件,提供IOC、AOP等基础功能,是Spring全家桶的基础。 Spring Boot:一个基于Spring Framework的快速开发框架,可以快速创建独立的、生产级别的…...
不同类型程序的句柄研究
先做一个winform程序;随便放几个控件; 用窗口句柄查看工具看一下;form和上面的每个控件都有一个句柄; 然后看一下记事本;记事本一共包含三个控件,各自有句柄; 这工具的使用是把右下角图标拖到要…...
【Godot】解决游戏中的孤立/孤儿节点及分析器性能问题的分析处理
Godot 4.1 因为我在游戏中发现,越运行游戏变得越来越卡,当你使用 Node 节点中的 print_orphan_nodes() 方法打印信息的时候,会出现如下的孤儿节点信息 孤儿节点信息是以 节点实例ID - Stray Node: 节点名称(Type: 节点类型) 作为格式输出&a…...
国家网络安全宣传周知识竞赛活动小程序界面分享
国家网络安全宣传周知识竞赛活动小程序界面分享...
mysql的判断语句
if if 用于做条件判断,具体的语法结构如下,在 if 条件判断的结构中, ELSE IF 结构可以有多个,也可以没有。 ELSE 结构可以有,也可以没有。 IF 条件1 THEN ..... ELSEIF 条件2 THEN -- 可选 ..... ELSE -- 可选 .....…...
ArcGIS Maps SDK for JavaScript系列之四:添加自定义底图
目录 Basemap类介绍Basemap类的常用属性Basemap类的常用方法 使用Basemap添加自定义底图引用Basemap引用切片图层创建一个新的Basemap对象将自定义图层应用到地图视图中引入并创建Camera对象引入并创建SceneView对象 Basemap类介绍 Basemap类是ArcGIS Maps SDK for JavaScript…...
Learn Prompt-角色扮演
模拟面试 当你在新闻中读到更多关于ChatGPT的内容时,你会听说ChatGPT可以代替医生、面试官、教师、律师等。但如果你想在实践中使用它,除了使用简单的提示或例子,你还可以根据不同的场景为ChatGPT设置不同的角色,这样我们就可以…...
《动手学深度学习 Pytorch版》 6.1 从全连接层到卷积
6.1.1 不变性 平移不变性(translation invariance): 不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应,即为“平移不变性”。 局部性(locality)&…...
六、数学建模之插值与拟合
1.概念 2.例题和matlab代码求解 一、概念 1.插值 (1)定义:插值是数学和统计学中的一种技术,用于估算在已知数据点之间的未知数据点的值。插值的目标是通过已知数据点之间的某种函数或方法来估计中间位置的数值。插值通常用于数…...
【项目经验】:elementui表格中数字汉字排序问题及字符串方法localeCompare()
一.需求 表格中数字汉字排序,数字按大小排列,汉字按拼音首字母(A-Z)排序。 二.用到的方法 第一步:把el-table-column上加上sortable"custom" <el-table-column prop"date" label"序号…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
