003-Spring boot 启动流程分析
目录
- 启动流程分析
- 创建 SpringApplication
- 启动 run(String... args)
- 读取配置流程分析
- listeners.environmentPrepared
- 解析配置文件详细分析
- EnvironmentPostProcessor 详细分析
启动流程分析
SpringApplication.run(App.class, args);return new SpringApplication(primarySources).run(args);
创建 SpringApplication
SpringApplication(primarySources):this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//这个推断流程 001 篇 分析webServer里有详情 web应用返回WebApplicationType.SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//获取Factories中配置的 BootstrapRegistryInitializer
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
this.initializers = getSpringFactoriesInstances(ApplicationContextInitializer.class);
this.listeners = getSpringFactoriesInstances(ApplicationListener.class));
//推断main方法所在的Class
this.mainApplicationClass = deduceMainApplicationClass();
启动 run(String… args)
//获取Factories中配置的 SpringApplicationRunListener 并执行其 starting()
SpringApplicationRunListeners listeners = getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args).forEach(listener.starting(bootstrapContext))
//封装 args:这里会读取执行jar的时候添加的以 '--' 开头的 kay=value
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//读取配置 包括:系统,JVM,ServletContext,properties,yaml配置
//全部设置到 environment 中
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//这一步我查资料应该是忽略Java解析BeanInfo的缓存 因为Spring使用的是ASM技术
configureIgnoreBeanInfo(environment);
//打印banner并返回
Banner printedBanner = printBanner(environment);
//根据类型返回上下文 001 有详细分析 AnnotationConfigServletWebServerApplicationContext
context = createApplicationContext();
context.applicationStartup = applicationStartup;
//利用ApplicationContextInitializer初始化Spring 上下文
//发布ApplicationContextInitializedEvent
//注册primarySources = run() 传入的配置类列表
//发布ApplicationContextPreparedEvent
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//调用refresh(context) 这一步就是执行Spring bean创建的逻辑了
refreshContext(context);
//这一步是空的 给子类一个实现的机会
afterRefresh(context, applicationArguments);
//遍历执行之前 listeners started()
listeners.started(context, timeTakenToStartup);
//执行 ApplicationRunner.run(args);
//执行 CommandLineRunner.run(args.getSourceArgs());
//两个执行器只有 入参的区别 一个是解析之后的对象,一个是字符串
callRunners(context, applicationArguments);
//遍历执行之前 listeners ready()
listeners.ready(context, timeTakenToReady);
读取配置流程分析
//读取配置 包括:系统,JVM,ServletContext,properties,yaml配置
//全部设置到 environment 中
prepareEnvironment(listeners, bootstrapContext, applicationArguments)://new ApplicationServletEnvironment();
//默认带有配置名称
//servletConfigInitParams 内容为空
//servletContextInitParams 内容为空
//systemProperties 内容为各种系统配置 如 java 版本、 -D开头的参数、OS版本等等
//systemEnvironment 内容为系统环境变量里的内容 如:JAVA_HOME、PATH等等
ConfigurableEnvironment environment = getOrCreateEnvironment();
//放入一个name:commandLineArgs
//解析 cmd 执行jar的时候带有的参数 就是 .jar 后配置的 不带 -D的
//解析后放入 new SimpleCommandLinePropertySource(args) 并放在第一个
//SimpleCommandLinePropertySource 有两个属性
//optionArgs 中放的是 带有 -- 的 key=value形式的参数 已经解析好了
//nonOptionArgs 中放的是 不带 -- 的参数 原样放进
configureEnvironment(environment, applicationArguments.getSourceArgs());
//设置到第一个 name:configurationProperties
//把 environment.getPropertySources() 设置进去
ConfigurationPropertySources.attach(environment);// 执行 EventPublishingRunListener#environmentPrepared
// 其实就发布了new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment))事件
// spring中的事件就是直接调用 所有的监听器 getListeners.froEach()
// 下边详细分析
listeners.environmentPrepared(bootstrapContext, environment);//绑定environment 到 SpringApplication
bindToSpringApplication(environment);//有可能是new出来的新的设置 到第一个 name:configurationProperties
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared
// 获取所有监听了 ApplicationEnvironmentPreparedEvent事件的监听器
EnvironmentPostProcessorApplicationListener : EnvironmentPostProcessor#postProcessEnvironment(environment, application)
AnsiOutputApplicationListener
LoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
FileEncodingApplicationListener
getApplicationListeners(event, type)
解析配置文件详细分析
EnvironmentPostProcessorApplicationListener 中
// EnvironmentPostProcessor 序号 有:
// CloudFoundryVcapEnvironmentPostProcessor Ordered.HIGHEST_PRECEDENCE + 9
// ConfigDataEnvironmentPostProcessor Ordered.HIGHEST_PRECEDENCE + 10
// RandomValuePropertySourceEnvironmentPostProcessor Ordered.HIGHEST_PRECEDENCE + 1
// SpringApplicationJsonEnvironmentPostProcessor Ordered.HIGHEST_PRECEDENCE + 5
// SystemEnvironmentPropertySourceEnvironmentPostProcessor Ordered.HIGHEST_PRECEDENCE + 4
// DebugAgentEnvironmentPostProcessor Ordered.LOWEST_PRECEDENCE
// IntegrationPropertiesEnvironmentPostProcessor Ordered.LOWEST_PRECEDENCE
for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),event.getBootstrapContext())) {postProcessor.postProcessEnvironment(environment, application);
}
EnvironmentPostProcessor 详细分析
按排序逐个执行
1.
RandomValuePropertySourceEnvironmentPostProcessor
添加一个 name为 random 的 RandomValuePropertySource 自动根据 getProperty(random.long)的类型返回随机数2.
SystemEnvironmentPropertySourceEnvironmentPostProcessor
这个就是把 systemEnvironment 内容重新包装成一个带有 prefix 字段的对象 具体有啥用没找到3.
SpringApplicationJsonEnvironmentPostProcessor
对 spring.application.json 和 SPRING_APPLICATION_JSON 配置进行JSON解析 这个解析比较早所以放在一般的配置文件里解析不到4.
CloudFoundryVcapEnvironmentPostProcessor
处理云服务器上的 VCAP_APPLICATION and VCAP_SERVICES JOSN变量 转化为 vcap.application. 或 vcap.services.开头的配置5.
ConfigDataEnvironmentPostProcessor
包含了2组解析路径
第一组> file:./;optional:file:./config/;optional:file:./config/*/
*/
第二组> optional:classpath:/;optional:classpath:/config/
遍历调用:
{StandardConfigDataLocationResolver} 文件名:spring.config.name 没有读取默认 application0 = {PropertiesPropertySourceLoader} 文件后缀:properties、xml1 = {YamlPropertySourceLoader} 文件后缀:yml、yaml
在解析的时候就现根据路径和文件名称文件后缀组成文件路径 20个(默认情况下:1个文件名 * 4中文件后缀 * 5个解析路径 = 20)
如: classpath:/application.properties, classpath:/application.yaml
挨个判断文件是否存在
存在的文件再解析内容6.
IntegrationPropertiesEnvironmentPostProcessor
处理 META-INF/spring.integration.properties 中指定的配置
已经规定好了解析的Key7.
DebugAgentEnvironmentPostProcessor
解析调试代理配置 spring.reactor.debug-agent.enabled
相关文章:
003-Spring boot 启动流程分析
目录 启动流程分析创建 SpringApplication启动 run(String... args) 读取配置流程分析listeners.environmentPrepared解析配置文件详细分析EnvironmentPostProcessor 详细分析 启动流程分析 SpringApplication.run(App.class, args);return new SpringApplication(primarySour…...
中间件的介绍
1.1 什么是中间件 中间件是介于应用系统和系统软件之间的一类软件,他使用系统软件所提供的基础服务,衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的。 例如MySQL就可以看作是具备中间件特性的一种技术&#x…...
LVS-DR模式下(RS检测)ldirectord工具实现部分节点掉点后将请求发往正常设备进行处理
基于前文的LVS-DR集群构建环境 一.下载ldirectord软件 二.将模板文件中的LVS-DR模式相关文件拷贝到/etc/ha.d主配置目录并按实际设备修改 三.配置两台RS匹配规则 四.停止RS1的http服务进行测试 RS1失去工作能力,RS2接替RS1 基于前文的LVS-DR集群构建环境 一.下…...
c++游戏制作指南(四):c++实现数据的存储和读取(输入流fstream)
🍿*★,*:.☆( ̄▽ ̄)/$:*.★* 🍿 🍟欢迎来到静渊隐者的csdn博文,本文是c游戏制作指南的一部🍟 🍕更多文章请点击下方链接🍕 🍨 c游戏制作指南dz…...
如何使用CSS实现一个响应式视频播放器?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现响应式视频播放器⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣…...
Typora上传文件到Gitee
工作内容,不对外开放 一、Typora上传笔记到CSDN 一、安装node.js 官网链接:Node.js (nodejs.org) 下载后得到一个.msi文件,双击即可。 win + R 打开CMD,基于node -v 和npm -v,验证是否安装成功: 二、配置Gitee 1、新建仓库 2、开源此仓库 2.1、初始化readme文件...
系统架构设计师---2017年下午试题1分析与解答(试题三)
2017年下午试题1分析与解答 试题三 阅读以下关于机器人操作系统架构的描述,回答问题1至问题3 【说明】 随着人工智能技术的发展,工业机器人已成为当前工业界的热点研究对象。某宇航设备公司为了扩大业务范围,决策层研究决定准备开展工业机器人研制新业务。公司将论证工作…...
从零搭建vue + element-plus 项目
目录 从零搭建vue element-plus 项目 环境安装 安装项目 安装命令如下: 选择配置如下: 安装插件与启动服务 安装element框架 使用element框架 测试element是否安装成功 环境判断 安装插件 使用插件 配置变量 暴漏变量 测试…...
原码、补码、反码
一、前置概念 计算机底层存储数据时使用的是二进制数字,但是计算机在存储一个数字时并不是直接存储该数字对应的二进制数字,而是存储该数字对应二进制数字的补码。所以接下来我们需要来了解一下原码、反码和补码。 那么再了解原码、反码、补码之前&…...
煤矿调度IP语音对讲广播模块一键求助对讲矿用调度通信系统SIP语音对讲求助终端
硬件接口描述 SV-2101VP/ SV-2103VP系列网络音频模块,所有外部连接采用端子,电源采用2.0mm的端子,网络采用标准RJ45连接器,其他都是1.25mm的连接器。 端口类型定义 P ———— 电源 AI ———— 模拟输入(在这里是音…...
堆 和 优先级队列(超详细讲解,就怕你学不会)
优先级队列 一、堆的概念特性二、堆的创建1、向下调整算法2、向下调整建堆3、向下调整建堆的时间复杂度 三、堆的插入1、向上调整算法实现插入2、插入创建堆的时间复杂度 三、堆的删除四、Java集合中的优先级队列1、PriorityQueue 接口概述及模拟实现2、如何创建大根堆…...
AIGC绘画:基于Stable Diffusion进行AI绘图
文章目录 AIGC深度学习模型绘画系统stable diffusion简介stable diffusion应用现状在线网站云端部署本地部署Stable Diffusion AIGC深度学习模型绘画系统 stable diffusion简介 Stable Diffusion是2022年发布的深度学习文本到图像生成模型,它主要用于根据文本的描述…...
python实现对Android系统手机亮度的调节
要实现对手机亮度的调节,需要使用Android系统的API。以下是一个简单的Python代码示例,演示如何使用ADB工具和Python脚本来控制Android设备的亮度: from adb.client import Client as AdbClient import os# 连接设备 client AdbClient(host&…...
《论文阅读14》FAST-LIO
一、论文 研究领域:激光雷达惯性测距框架论文:FAST-LIO: A Fast, Robust LiDAR-inertial Odometry Package by Tightly-Coupled Iterated Kalman Filter IEEE Robotics and Automation Letters, 2021 香港大学火星实验室 论文链接论文github 二、论文概…...
Kotlin CompletableDeferred 入门
在 Kotlin 中,CompletableDeferred 是一个用于异步编程的类,它提供了一种实现异步操作和等待操作结果的方式。 CompletableDeferred 是 Deferred 接口的具体实现之一,可以用于表示一个可能会在将来完成的操作。它提供了以下主要功能…...
stm32g070的PD0/PD2 PA8和PB15
目前在用STM32G070做项目,其中PD2TIMER3去模拟PWM,PD0用作按键检测,测试发现PD0低电平检测没有问题,高电平检测不到,电路图如下图所示: 用万用表测试电平,高电平1.0V左右,首先怀疑硬…...
【数据结构】 链表简介与单链表的实现
文章目录 ArrayList的缺陷链表链表的概念及结构链表的分类单向或者双向带头或者不带头循环或者非循环 单链表的实现创建单链表遍历链表得到单链表的长度查找是否包含关键字头插法尾插法任意位置插入删除第一次出现关键字为key的节点删除所有值为key的节点回收链表 总结 ArrayLi…...
【Leetcode】98. 验证二叉搜索树
一、题目 1、题目描述 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。示例1: 输入:root = …...
ViewFs And Federation On HDFS
序言 ViewFs 是在Federation的基础上提出的,用于通过一个HDFS路径来访问多个NameSpace,同时与ViewFs搭配的技术是client-side mount table(这个就是具体的规则配置信息可以放置在core.xml中,也可以放置在mountTable.xml中). 总的来说ViewFs的其实就是一个中间层,用于去连接不…...
每日一学——无线基础知识
无线局域网(Wireless Local Area Network,简称 WLAN)是一种使用无线通信技术连接多个无线终端设备的局域网。它通常基于无线电波传输数据,并使用无线接入点(Access Point,简称 AP)来连接无线设备…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
