spring boot启动源码分析(三)之Environment准备
上一篇《spring-boot启动源码分析(二)之SpringApplicationRunListener》
环境介绍:
spring boot版本:2.7.18
主要starter:spring-boot-starter-web
本篇开始讲启动过程中Environment环境准备,Environment是管理所有配置的实例对象,像application.yml、系统属性、环境变量等配置都可以通过Environment.getProperty(key)获取
入口如下:
(一)创建ConfigurableEnvironment
首先会从spring.factories中获取ApplicationContextFactory.class接口实现类,根据webApplicationType会实例化对应的ConfigurableEnvironment(这里是SERVLET,所以是AnnotationConfigServletWebServerApplicationContext.Factory创建的ApplicationServletEnvironment)
ApplicationServletEnvironment的类结构如下:
ApplicationServletEnvironment调用构造方法实例化时,父类AbstractEnvironment构造方法中会有初始化操作:
propertySources是Environment的核心属性,包含了各个配置源,这里赋值了一个MutablePropertySources,它实际是一个迭代器:
propertyResolver:是属性解析器,如占位符的解析等
AbstractEnvironment构造器采用类似模板方法将customizePropertySources(propertySources)交给子类实现,子类可以在此方法中加载数据源
可以看到子类StandardServletEnvironment,添加了StubPropertySource,桩配置源,类似打桩,这两个桩配置源分别是servletConfigInitParams和servletContextInitParams。这两个在webserver启动后会被替换成实际的配置源,这里只是个站位,没有实际的作用。
之后再次调用超类的customizePropertySources:
在StandardEnvironment中会添加两个重要的配置源,systemProperties和systemEnvironment。
systemProperties对应System.getProperties(),即所有的系统属性:
systemEnvironment对应的是System.getenv(),即系统的所有环境变量
(二)对Environment进行其他配置
(1)首先添加conversionService:environment中的propertyResolver(配置解析器)配置应用转换服务,例如NumberToNumberConverterFactory,StringToCharacterConverter等。应该是为propertyResource中的数据解析时进行数据转换用的
(2)configurePropertySources:
如果SpringApplication中Map<String, Object> defaultProperties不为空,则会创建一个名为“defaultProperties”,实例类型为DefaultPropertiesPropertySource的配置源。
java进程传入的命令行参数加载进配置源中,配置源名称为commandLineArgs,实例类型为CommandLinePropertySource。此方法为模板方法,可被子类覆盖实现自己的资源加载方式configureProfiles
(3)此为空实现,看注释是说配置此应用程序环境中哪些配置文件处于活动状态(或默认情况下处于活动状态)。在配置文件处理过程中,可以通过{@code-spring.profiles.active}属性激活其他配置文件。
(三)绑定ConfigurationPropertySources
ConfigurationPropertySources.attach(environment);
增加一个名为“configurationProperties”的ConfigurationPropertySourcesPropertySource和environment绑定,实际上是把environment中所有的propertySource(也包括configurationProperties)包装进一个SpringConfigurationPropertySources实例中,而SpringConfigurationPropertySources是ConfigurationPropertySourcesPropertySource中的一个属性值,这也意味着configurationProperties可以访问所有的propertySource,这样它可以作为配置的统一访问入口。可以看如下configurationProperties对应实例属性
所以ConfigurationPropertySourcesPropertySource.getProperty(String name),实际上就是遍历每个PropertySource,获取它们的配置,但它对每个PropertySource进行了适配,以便以统一的接口进行获取配置。
getSource获取的是SpringConfigurationPropertySources,是一个迭代器,iterator()中会对配置源进行适配,适配成ConfigurationPropertySource
(四)发布environmentPrepared事件
事件的发布流程都差不多,这里不再赘述。主要差别是哪些监听器会监听了此事件,并做了什么逻辑处理。这里我们重点说一下这个:
主要有6个监听器:
代理监听器可以跳过,没有实际的逻辑处理。我们关注spring boot自定义的监听器。
(1)EnvironmentPostProcessorApplicationListener
这里主要是从spring.fatories获取EnvironmentPostProcessor接口实现类并实例化:
然后调用对应postProcessEnvironment,这些EnvironmentPostProcessor主要是添加不同的数据源配置,如ConfigDataEnvironmentPostProcessor解析我们常用的application.yml作为配置源,详情可看《Spring boot源码之EnvironmentPostProcessor》
(2)AnsiOutputApplicationListener
这里主要是根据spring.output.ansi.enabled和spring.output.ansi.console-available,设置AnsiOutput对应的属性。为输出到控制台的日志信息添加 ANSI 转义码,以实现彩色输出。这个用的比较少,我看只在打印banner和logback日志的颜色转换器中用到了
(3)LoggingApplicationListener
在上一篇发布starting事件中,日志系统进行了初步初始化,在这里则会完成全部的初始化。
a、getLoggingSystemProperties(environment).apply():会将配置文件中配置的日志相关配置设置到系统属性中,以便后续日志系统初始化时可以从系统属性读取。
如:配置文件中如果设置了logging.pattern.console,那么就会设置到系统属性变量CONSOLE_LOG_PATTERN中。这里还设置了PID以及下面的日志策略
b、initializeEarlyLoggingLevel(environment):初始化早期日志级别,实际只是根据Environment中是否配置debug和trace,设置springBootLogging对应级别
c、initializeSystem(environment, this.loggingSystem, this.logFile):这里是主要的初始化逻辑,如果之前日志已经初始化过,这里会使用spring boot会重新初始化,对日志进行增强。比如在logback中,会使用SpringBootJoranConfigurator,对配置文件进行加载解析,同时新定义了一些解析规则
所以在spring boot中可以使用springProperty,添加属性,值可以是Environment中配置的属性值
如上,是配置了一个pid变量,值是Environment中pid属性对应的属性值
d、initializeFinalLoggingLevels(environment, this.loggingSystem):初始化日志的最终的日志级别:
如果b步骤设置了springBootLogging,那么spring boot会初始化一些logger,设置其日志级别,如过是debug级别,则下图圈出来的都会设置是debug级别
另外则是对配置属性中有logging.level为前缀的设置其对应的日志级别:
如上,则会设置com.example为true。
e、registerShutdownHookIfNecessary(environment, this.loggingSystem)
往SpringApplication注册日志系统的shutdownHandler,会在shutdown发生时,停止日志上下文。
(4)BackgroundPreinitializer
启动一个后台线程去出发早期的初始化,并且有个countDownLatch,只有初始化完成,当ApplicationReadyEvent监听触发时,得等线程执行完才会继续执行,否则等待
(5)FileEncodingApplicationListener
当系统设置了spring.mandatory-file-encoding编码格式时,会判断是否和System.getProperty("file.encoding")相同,如果不相等则抛出异常阻止系统的启动,默认没设置不影响
(五)其他
上面基本已经把环境变量准备完毕,剩下的是一些细微处理:
(1)将defaultProperties配置源移到最后,即查询资源时最后才查它
(2)SpringApplication相关环境变量绑定
即将spring.main开头的配置,绑定到对应SpringApplication的属性中。如spring.main.allow-circular-references=true,那么就会设置SpringApplication的allowCircularReferences值为true.
(3)Environment转换ConfigurableEnvironment为应用类型的环境,这里是ApplicationServletEnvironment,是ConfigurableEnvironment的子类,不需要转换
相关文章:

spring boot启动源码分析(三)之Environment准备
上一篇《spring-boot启动源码分析(二)之SpringApplicationRunListener》 环境介绍: spring boot版本:2.7.18 主要starter:spring-boot-starter-web 本篇开始讲启动过程中Environment环境准备,Environment是管理所有…...

MySQL复习
基础篇 InnoDB、MyISAM 和 MEMORY 存储引擎的区别? 主要区别: 为什么MySQL选择 InnoDB 作为默认存储引擎? 1.innodb支持事务,myisam、memory不支持。 2.innodb支持行级锁,可以使多个事务同时访问不同的行…...
ASP.NET Core 实现微服务 -- Polly 服务降级熔断
在我们实施微服务之后,服务间的调用变的异常频繁。多个服务之间可能是互相依赖的关系。某个服务出现故障或者是服务间的网络出现故障都会造成服务调用的失败,进而影响到某个业务服务处理失败。某一个服务调用失败轻则造成当前相关业务无法处理࿱…...

服务器漏洞修复解决方案
漏洞1、远程桌面授权服务启用检测【原理扫描】 Windows Remote Desktop Licensing Service is running: Get Server version: 0x60000604 1、解决方案:建议禁用相关服务避免目标被利用 方法一:使用服务管理器 打开“运行”对话框(WinR&am…...

“AI智慧组卷系统:让考试变得更简单、更公平!
大家好,我是一名资深的产品经理,今天咱们就来聊聊教育领域的一款黑科技产品——AI智慧组卷系统。在这个信息技术飞速发展的时代,AI技术已经渗透到了我们生活的方方面面,教育行业也不例外。下面我就用大白话给大家介绍一下这个AI智…...

MT6706BL 同步整流 规格书
MT6706BL 是用于反激式变换器的高性能 65V 同步整流器。MT6706BL兼容各种反激转换器类型。MT6706BL 支持 DCM、CCM 和准谐振模式。MT6706BL 集 成 了 一 个 65V 功 率MOSFET,可以取代肖特基二极管,提高效率。V SW <V TH-ON 时,MT6706BL 内…...

vue el-table 数据变化后,高度渲染问题
场景:el-table设置了height属性,但是切换查询条件后再次点击查询重新获取data时,el-table渲染的高度会有问题,滚动区域变矮了。 解决办法:使用doLayout方法,在表格数据渲染后调用doLayout方法可以重新布局…...
前端多语言
前端多语言目前常用i18n实现 一、react 1.安装依赖 npm install react-i18next i18next --save2.创建配置文件 src/i18n config.ts:对 i18n 进行初始化操作及插件配置 en.json:英文语言配置文件 zh.json:中文语言配置文件 config.ts im…...

人工智能-机器学习之多元线性回归(项目实践一)
目标:运用scikit-learn进行多元线性回归方程的构建,通过实际案例的训练集和测试集进行预测,最终通过预测结果和MSE来评估预测的精度。 一、首先安装scikit-learn:pip install scikit-learn C:\Users\CMCC\PycharmProjects\AiPro…...
后台定时查杀进程策略
2019年做的一个500元价位内手机后台定时查杀的功能策略,现在2025年了回过头看,确实已经不适用了。现在进程管控大部分是不杀进程的方式了,类似冻结(类似苹果的墓碑机制),而杀进程策略主要是场景式异常查杀了,例如明显性…...
Objective-C语言的学习路线
Objective-C语言的学习路线 在程序开发的历史长河中,Objective-C作为一种继承自C语言与Smalltalk的编程语言,扮演着重要的角色。虽然随着Swift语言的出现,Objective-C的使用有所减少,但它依然是iOS和macOS应用开发的重要基础&…...

宁德时代2025年Verify入职测评语言理解及数字推理真题SHL题库汇总、考情分析
宁德时代社招Verify入职测评对薪酬有着重要影响,其规定正确率达到80%才能顺利通过测评。这体现了公司对人才专业素养与能力的严格要求,旨在筛选出真正符合岗位需求的优秀人才。测评内容涵盖了专业知识、技能运用、逻辑思维等多方面,只有综合能…...

【Spring】注入方式
介绍 在Spring框架中,依赖注入(Dependency Injection, DI)是实现控制反转(Inversion of Control, IoC)的核心机制。 除了通过XML配置的注入方式(已逐渐被淘汰),Spring还支持多种基…...
Python 中的作用域:规则与应用
在 Python 编程中,作用域(Scope) 是指一个变量可以被访问和引用的范围。作用域与变量的生命周期密切相关,决定了变量何时被创建、何时被销毁以及在哪些地方可以使用它。理解作用域对于编写清晰、可维护的代码至关重要。 Python 中…...
T-SQL语言的字符串处理
T-SQL语言的字符串处理 引言 在数据库管理和应用开发中,我们经常需要对字符串进行处理。字符串的处理包括查找、替换、分割、拼接以及格式化等操作,而这些操作在SQL Server中可以通过T-SQL(Transact-SQL)来实现。T-SQL是微软SQL…...

宇航用VIRTEX5系列FPGA的动态刷新方法及实现
SRAM型FPGA在宇航领域有广泛的应用,为解决FPGA在空间环境中的单粒子翻转问题,增强设计的可靠性,本文介绍一种低成本的抗辐照解决方案。该方案从外置高可靠存储器中读取配置数据,通过定时刷新结合三模冗余的方式消除单粒子影响&…...
Flink提交任务通过Kerberos认证
Flink提交任务通过Kerberos认证 Clouera官网地址: https://docs.cloudera.com/csa/1.7.0/security/topics/csa-securing-jobs.html Securing Apache Flink jobs flink run -d -p 2 \ -yD security.kerberos.login.keytabtest.keytab \ -yD security.kerberos.lo…...
【linux】文件与目录命令 - cp
文章目录 1. 基本用法2. 常用参数3. 用法举例4. 注意事项 cp 命令用于复制文件或目录,支持单个文件复制、多文件复制以及目录的递归复制,是 Linux 系统中常用的文件管理命令之一。 1. 基本用法 语法: cp [选项] 源文件 目标文件 cp [选项] …...

鸿蒙--登入案例
实现要求: 在账户和密码的输入框输入账号或密码时,提交按钮下方同步出现输入的账户和密码 Entry Component struct login {State username:string State password:string build() {Column(){// 图标Image($r(app.media.app_icon)).width(100).height(…...

【JavaWeb】EL表达式
目录 1.EL表达式概述 2.EL表达式运算 3.EL表达式操作对象 4.EL表达式内置对象 4.1.参数隐藏对象 4.2.域隐藏对象 4.3.PageContext对象 1.EL表达式概述 EL(Expression Language)是一门表达式语言,它对应<% ... %>。在JSP中&…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
学习一下用鸿蒙DevEco Studio HarmonyOS5实现百度地图
在鸿蒙(HarmonyOS5)中集成百度地图,可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API,可以构建跨设备的定位、导航和地图展示功能。 1. 鸿蒙环境准备 开发工具:下载安装 De…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...