当前位置: 首页 > news >正文

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类型的对象&#xff0c;这个对象就是用于存储配置&#xff0c;如图springboot会在启动的最开始创建一个Environment对象 这个webApplicationType的枚举是在new SpringAppli…...

Android 使用Camera1实现相机预览、拍照、录像

1. 前言 本文介绍如何从零开始&#xff0c;在Android中实现Camera1的接入&#xff0c;并在文末提供Camera1Manager工具类&#xff0c;可以用于快速接入Camera1。 Android Camera1 API虽然已经被Google废弃&#xff0c;但有些场景下不得不使用。 并且Camera1返回的帧数据是NV21…...

2024字节跳动校招面试真题汇总及其解答(四)

12.Java的类加载机制 Java的类加载机制是指将描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。 类的加载过程分为以下五个阶段: 加载:将Class文件从磁盘读入内存,并…...

网页的快捷方式打开自动全屏--Chrome、Firefox 浏览器相关设置

Firefox 的全屏方式与 Chrome 不同&#xff0c;Chrome 自带全屏模式以及APP模式&#xff0c;通过简单的参数即可设置&#xff0c;而Firefox暂时么有这个功能&#xff0c;Firefox 的全屏功能可以通过全屏插件实现。 全屏模式下&#xff0c;按 F11 不会退出全屏&#xff0c;鼠标…...

LabVIEW使用ModbusTCP协议构建分布式测量系统

LabVIEW使用ModbusTCP协议构建分布式测量系统 分布式测量系统主要用于监控远程物体。这种系统允许对系统用户获得的数据进行全面的数据收集、处理、存储和组织访问。它们可能包括许多不同类型的传感器。 在任何具有互联网接入的个人计算机上运行的软件都会发送来自传感器的测…...

unity学习第1天

本身也具有一些unity知识&#xff0c;包括Eidtor界面使用、Shader效果实现、性能分析&#xff0c;但对C#、游戏逻辑不太清楚&#xff0c;这次想从开发者角度理解游戏&#xff0c;提高C#编程&#xff0c;从简单的unity游戏理解游戏逻辑&#xff0c;更好的为工作服务。 unity201…...

Spring Boot实现对文件进行压缩下载

在Web应用中&#xff0c;文件下载功能是一个常见的需求&#xff0c;特别是当你需要提供用户下载各种类型的文件时。本文将演示如何使用Spring Boot框架来实现一个简单而强大的文件下载功能。我们将创建一个RESTful API&#xff0c;通过该API&#xff0c;用户可以下载问价为ZIP压…...

Mac专用投屏工具AirServer 7 .27 for Mac中文免费激活版

AirServer 7 .27 for Mac中文免费激活版是一款Mac专用投屏工具&#xff0c;能够通过本地网络将音频、照片、视频以及支持AirPlay功能的第三方App&#xff0c;从 iOS 设备无线传送到 Mac 电脑的屏幕上&#xff0c;把Mac变成一个AirPlay终端的实用工具。 目前最新的AirServer 7.2…...

LabVIEW使用巴特沃兹低通滤波器过滤噪声

LabVIEW使用巴特沃兹低通滤波器过滤噪声 设备采集到的数据往往都有噪声&#xff0c;有时候这些数据要做判断使用&#xff0c;如果不处理往往会影响最终的结果。可以使用动态平滑&#xff0c;或者中值滤波等方法。这里介绍使用巴特沃斯低通滤波&#xff0c;也是非常方便的。 下…...

【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&#xff1a;Spring的核心组件&#xff0c;提供IOC、AOP等基础功能&#xff0c;是Spring全家桶的基础。 Spring Boot&#xff1a;一个基于Spring Framework的快速开发框架&#xff0c;可以快速创建独立的、生产级别的…...

不同类型程序的句柄研究

先做一个winform程序&#xff1b;随便放几个控件&#xff1b; 用窗口句柄查看工具看一下&#xff1b;form和上面的每个控件都有一个句柄&#xff1b; 然后看一下记事本&#xff1b;记事本一共包含三个控件&#xff0c;各自有句柄&#xff1b; 这工具的使用是把右下角图标拖到要…...

【Godot】解决游戏中的孤立/孤儿节点及分析器性能问题的分析处理

Godot 4.1 因为我在游戏中发现&#xff0c;越运行游戏变得越来越卡&#xff0c;当你使用 Node 节点中的 print_orphan_nodes() 方法打印信息的时候&#xff0c;会出现如下的孤儿节点信息 孤儿节点信息是以 节点实例ID - Stray Node: 节点名称(Type: 节点类型) 作为格式输出&a…...

国家网络安全宣传周知识竞赛活动小程序界面分享

国家网络安全宣传周知识竞赛活动小程序界面分享...

mysql的判断语句

if if 用于做条件判断&#xff0c;具体的语法结构如下&#xff0c;在 if 条件判断的结构中&#xff0c; ELSE IF 结构可以有多个&#xff0c;也可以没有。 ELSE 结构可以有&#xff0c;也可以没有。 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的内容时&#xff0c;你会听说ChatGPT可以代替医生、面试官、教师、律师等。但如果你想在实践中使用它&#xff0c;除了使用简单的提示或例子&#xff0c;你还可以根据不同的场景为ChatGPT设置不同的角色&#xff0c;这样我们就可以…...

《动手学深度学习 Pytorch版》 6.1 从全连接层到卷积

6.1.1 不变性 平移不变性&#xff08;translation invariance&#xff09;&#xff1a; 不管检测对象出现在图像中的哪个位置&#xff0c;神经网络的前面几层应该对相同的图像区域具有相似的反应&#xff0c;即为“平移不变性”。 局部性&#xff08;locality&#xff09;&…...

六、数学建模之插值与拟合

1.概念 2.例题和matlab代码求解 一、概念 1.插值 &#xff08;1&#xff09;定义&#xff1a;插值是数学和统计学中的一种技术&#xff0c;用于估算在已知数据点之间的未知数据点的值。插值的目标是通过已知数据点之间的某种函数或方法来估计中间位置的数值。插值通常用于数…...

【项目经验】:elementui表格中数字汉字排序问题及字符串方法localeCompare()

一.需求 表格中数字汉字排序&#xff0c;数字按大小排列&#xff0c;汉字按拼音首字母&#xff08;A-Z&#xff09;排序。 二.用到的方法 第一步&#xff1a;把el-table-column上加上sortable"custom" <el-table-column prop"date" label"序号…...

Spring Boot的运行原理

Spring Boot的运行原理 Spring Boot是一个用于快速构建独立、可独立运行的Spring应用程序的框架。它通过自动配置和约定优于配置的原则&#xff0c;简化了Spring应用程序的开发过程。下面将详细介绍Spring Boot的运行原理&#xff0c;并附上一些代码解释。 1. 主要组件 Sprin…...

xen-gic初始化流程

xen-gic初始化流程 调试平台使用的是gic-600&#xff0c;建议参考下面的文档来阅读代码&#xff0c;搞清楚相关寄存器的功能。 《corelink_gic600_generic_interrupt_controller_technical_reference_manual_100336_0106_00_en》 《IHI0069H_gic_architecture_specification》…...

Docker从认识到实践再到底层原理(六-1)|Docker容器基本介绍+命令详解

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…...

【Flink】FlinkCDC自定义反序列化器

在我们用FlinkCDC采集mysql数据(或其他数据源)的时候,FlinkCDC输出的格式不标准,不利于我们后续做数据处理,我们通常会使用自定义反序列化器来格式化采集数据方便后续处理 常规的反序列化器如下: public class FlinkDataStreamCDC {public static void main(String[] ar…...

linux基础(2)

目录 一.vi\vim编译器介绍1.三种模式2.vim的使用3.快捷键的使用 二.which&#xff0c;find命令三.grep命令四.wc命令五.管道符六.echo命令1.重定向符 七.tail命令 一.vi\vim编译器介绍 vim\vi是linux中最经典的文本编译器 同图形化界面中的文本编译器是一样的&#xff0c;vi是…...

docker安装zookeeper(单机版)

第一步&#xff1a;拉取镜像 docker pull zookeeper第二步&#xff1a;启动zookeeper docker run -d -e TZ"Asia/Shanghai" -p 2181:2181 -v /home/sunyuhua/docker/zookeeper:/data --name zookeeper --restart always zookeeper...

国际版阿里云/腾讯云免开户:云存储服务:云存储服务能够让你随时随地拜访和同享文件

云存储服务&#xff1a;云存储服务能够让你随时随地拜访和同享文件 云存储服务是一种基于云技术的存储渠道&#xff0c;能够让用户存储、管理和同享各种类型的数据文件&#xff0c;如文档、图片、视频、音频等。这种服务具有许多长处&#xff0c;以下是对其进行的详细分析&…...

【Java】应用层协议HTTP和HTTPS

HTTP和HTTPS协议 HTTPHTTP协议的工作过程HTTP协议格式抓包工具抓包结果 HTTP请求(Request)URL方法GET方法POST请求其他方法 报头(header)HostContent-lengthContent-TypeUser-AgentRefererCookie 正文(body) HTTP响应HTTP状态码响应报头(header)响应正文(body) 通过form表单构造…...

SpringBoot整合Flowable

1. 配置 &#xff08;1&#xff09; 引入maven依赖 <dependency><groupId>org.flowable</groupId><artifactId>flowable-spring-boot-starter</artifactId><version>6.7.2</version></dependency><!-- MySQL连接 -->&l…...

华为云香港S3云服务器性能测评_99元一年租用价格

华为云香港S3云服务器1核2G1M带宽99元一年性能测评&#xff0c;配置为S3云服务器1核2G1M带宽&#xff0c;S系列热卖机型&#xff0c;适用于个人建站、普通web应用等负载较低场景&#xff0c;系统盘为高IO40G系统盘&#xff0c;华为云百科分享华为云香港云服务器配置费用&#x…...

黑龙江省建设教育信息网网站/google浏览器官网

GRUB的功能1. 提供选择要启动的内核或者系统2. 提供交互式接口。进入GRUB后按e键进入GRUB的交互接口&#xff0c;可已经行Linux系统运行基本的选择。3. 基于密码的保护&#xff1a;启用内核映像&#xff0c;传递参数12341234GRUB的接口格式title&#xff1a;操作系统的内核或者…...

飞沐网站设计/营销推广方案

我有一个网络,我正在使用vis.js构建,但它在宽度方面太大,无法放入页面的容器中.网络从左到右运行,包含有关特定进程的步骤.当一个人完成任务时,服务器会提供新的JSON记录来更新颜色.由于布局,我无法更改容器大小.当网络加载时,它会导致字体非常小且不可读.有没有办法可以将缩放…...

zblog换wordpress/网络推广怎么做

之前用的opencore来配置黑苹果结果卡在这个地方死活进不去 [IGPU] Scheduler Throttle Cap100ms 之后去bios里面把igpu关掉就行了。 选择高级 选择北桥 选择显示设置 把初始化IGPU关了。 我现在ASUS B360M的主板&#xff0c;蓝宝石白金vega56&#xff0c;i7-8700的cpu&…...

wordpress 插件 免费/手机营销推广方案

第1步、MVC2 > MVC3 手动处理可以参考这个&#xff1a;http://www.asp.net/whitepapers/mvc3-release-notes#upgrading 使用工具 ASP.NET MVC 3 Application Upgraderhttp://aspnet.codeplex.com/releases/view/59008 这个工具要求VS2010的项目&#xff0c;sln文件头为&…...

网站建设沈阳/关键词指数

作者&#xff1a;小傅哥 博客&#xff1a;https://bugstack.cn 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 一、前言 为什么&#xff0c;读不懂框架源码&#xff1f; 我们都知道作为一个程序员&#xff0c;如果想学习到更深层次的技术&…...

专业网站建设怎么样/广州seo推荐

题目&#xff1a;原题链接&#xff08;简单&#xff09; 解法时间复杂度空间复杂度执行用时Ans 1 (Python)O(n)O(1)40ms (87.66%)Ans 2 (Python)––44ms (71.54%)Ans 2 (Python)––40ms (87.66%)LeetCode的Python执行用时随缘&#xff0c;只要时间复杂度没有明显差异&#x…...