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的子类,不需要转换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/65589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springmvc前端传参,后端接收

RequestMapping注解 Target({ElementType.METHOD, ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Documented Mapping public interface RequestMapping {String name() default "";AliasFor("path")String[] value() default {};AliasFor(&quo…

【Excel/WPS】根据平均值,生成两列/多列指定范围的随机数/随机凑出两列数据

原理就是通过随机生成函数和平均值函数。 适用场景&#xff1a;在总体打分后&#xff0c;需要在小项中随机生成小分数 第一列&#xff1a;固定的平均值A2第二列&#xff1a; RANDBETWEEN(A2-10,A210)第三列&#xff1a;根据第二列用平均值函数算除 A2*2-B2这是随机值1的公式&am…

运动相机拍摄的视频打不开怎么办

3-10 GoPro和大疆DJI运动相机的特点&#xff0c;小巧、高清、续航长、拍摄稳定&#xff0c;很多人会在一些重要场合用来拍摄视频&#xff0c;比如可以用来拿在手里拍摄快速运动中的人等等。 但是毕竟是电子产品&#xff0c;有时候是会出点问题的&#xff0c;比如意外断电、摔重…

智能化文档开发(DI)

这个文档涉及到多模态&#xff08;文本、发票、订单、语音&#xff09; 对于普通的文本&#xff0c;我们希望对某些实体的某些属性挖空生成文档模版&#xff0c;并根据预设字段填空最后生成正式文件对于发票、订单&#xff0c;我们想提取它的字段信息&#xff0c;写入DB对于一些…

【轻松学C:编程小白的大冒险】--- C语言简介 02

在编程的艺术世界里&#xff0c;代码和灵感需要寻找到最佳的交融点&#xff0c;才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里&#xff0c;我们将共同追寻这种完美结合&#xff0c;为未来的世界留下属于我们的独特印记。 【轻松学C&#xff1a;编程小白的大冒险】…

零基础 监控数据可视化 Spring Boot 2.x(Actuator + Prometheus + Grafana手把手) (上)

一、安装Prometheus Releases prometheus/prometheus GitHubhttps://github.com/prometheus/prometheus/releases 或 https://prometheus.io/download/https://prometheus.io/download/ 1. 下载适用于 Windows 的二进制文件&#xff1a; 找到最新版本的发布页面&#xf…

Idea日志乱码

问题描述 前提&#xff1a;本人使用windows Idea运行sh文件&#xff0c;指定了utf-8编码&#xff0c;但是运行过程中还是存在中文乱码 Idea的相关配置都已经调整 字体调整为雅黑 文件编码均调整为UTF-8 调整Idea配置文件 但是还是存在乱码&#xff0c;既然Idea相关配置已经…

MySQL 数据表与索引设计艺术:打造高效数据存取架构

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《MySQL技术精粹》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是MySQL 2、MySQL适用场景 二、MySQL的数据存储与检索 1、数据表…

安卓硬件加速hwui

安卓硬件加速 本文基于安卓11。 从 Android 3.0 (API 级别 11) 开始&#xff0c;Android 2D 渲染管道支持硬件加速&#xff0c;这意味着在 View 的画布上执行的所有绘图操作都使用 GPU。由于启用硬件加速所需的资源增加&#xff0c;你的应用程序将消耗更多内存。 软件绘制&am…

海信116英寸RGB-Mini LED:一朵绽放在科技穹顶的中国花火

东方古镇的打铁花&#xff0c;拉斯维加斯的烟花秀&#xff0c;盛大的花火表演总会在岁末年初的时候&#xff0c;吸引世界各地人们的目光。一年一度的科技展会&#xff0c;也起到烟花秀一样的作用&#xff0c;让人们提前望见未知的精彩。 CES还没开始&#xff0c;CES 2025展会的…

积分漏斗模型中5个指标统计

缘起 最近遇到一个积分漏斗模型的设计&#xff0c;这里记录一下。以防止以后忘记了。其中毕竟关键的属性是&#xff1a; 获得积分可用积分已有积分 积分漏斗模型 这里随着【当前日期】也就是今天日期。随着时间一天天过去&#xff0c;积分也一天天过去。上面那个【填报时间】…

Ubuntu挂载Windows 磁盘,双系统

首先我们需要在终端输入这个命令&#xff0c;来查看磁盘分配情况 lsblk -f 找到需要挂载的磁盘&#xff0c;检查其类型&#xff08; 我的/dev/nvme2n1p1类型是ntfs&#xff0c;名字叫3500winData&#xff09; 然后新建一个挂载磁盘的目录&#xff0c;我的是/media/zeqi/3500wi…

Web渗透测试之XSS跨站脚本攻击 跨域是什么?同源机制又是什么? cors以及Jsonp是什么 一篇文章给你说明白

目录 Cookie的Httponly属性和逃过方式 浏览器同源机制 cors跨域和jsonp跨域和跨域标签 Cors跨域 - 跨源 Jsonp 跨域 jsonp跨域原理&#xff1a; 说明: Cookie的Httponly属性和逃过方式 Xss攻击手段 最常用的目的获取cookie Cookie中设置了 httponlyTrue 方式js操作获…

【C++】字符串的 += 和 + 运算详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;1. 字符串的 和 基本用法1.1 的用法1.2 的用法 &#x1f4af;2. 示例代码的剖析与解释代码分析 &#x1f4af;3. 底层实现与性能分析3.1 的实现原理3.2 的实现原理3.…

CCLINK转MODBUS-TCP协议转换网关模块应用案例

大家好&#xff0c;今天我们要聊的是生产管理系统中的CCLINK和MODBUS-TCP协议&#xff0c;它们的不同使得数据互通比较困难&#xff0c;但捷米特JM-CCLK-TCP网关的出现改变了这一切。 为了实现整个生产线的协同工作&#xff0c;需要这些设备之间能够进行有效的数据交换和指令传…

Go学习:多重赋值与匿名变量

1. 变量的多重赋值 1.1 基本语法格式 go语言中&#xff0c;可以将多个赋值语句 合并成 一句&#xff0c;比如&#xff1a; a : 10 b : 20 c : 30//a,b,c三个变量的赋值语句可以简练成以下格式a, b, c : 10, 20, 30 1.2 交换变量值 当需要交换两个变量的值时&#…

Spring——依赖注入之p命名空间和c命名空间

p命名空间 其实就是Set注入 只不过p命名空间写法更简洁 p可以理解为 property标签的首字母p p命名空间依赖于set方法 依赖引入 使用前需要再配置文件头文件中引入p命名空间的依赖&#xff1a; ** xmlns:p“http://www.springframework.org/schema/p” ** 用法 在bean标签…

【Linux】Linux常见指令(上)

个人主页~ 初识Linux 一、Linux基本命令1、ls指令2、pwd命令3、cd指令4、touch指令5、mkdir指令6、rmdir指令7、rm指令8、man指令9、cp指令10、mv命令 Linux是一个开源的、稳定的、安全的、灵活的操作系统&#xff0c;Linux下的操作都是通过指令来实现的 一、Linux基本命令 先…

【Vue.js 组件化】高效组件管理与自动化实践指南

文章目录 摘要引言组件命名规范与组织结构命名规范目录组织 依赖管理工具自动化组件文档生成构建自动引入和文档生成的组件化体系代码结构自动引入组件配置使用 Storybook 展示组件文档自动生成 代码详解QA 环节总结参考资料 摘要 在现代前端开发中&#xff0c;组件化管理是 V…

【Arthas命令实践】heapdump实现原理

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 使用原理 使用 dump java heap, 类似 jmap 命令的 heap dump 功能。 【dump 到指定文件】 heapdump arthas-output/dump.hprof【只 …