SpringBoot2.7 核心源码解读
配置解析
从生命周期章节我们知道配置文件的解析是发生在EnvironmentPostProcessorApplicationListener执行环境后置处理器的过程中,通过从spring.factories中获取所有实现了EnvironmentPostProcessor接口的配置类,如下:
- org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor
- org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor
- org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor
- org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
- org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
- org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
- org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor
实例化并排序后顺序如下:
org.springframework.boot.env.RandomValuePropertySourceEnvironmentPostProcessor
… 添加一个名为random的属性源到Environment中
… 通过诸如abc=${random.int(11,22)}配置,表示随机一个整数在11至22之间
… 底层直接使用Random类实现org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
… 将SystemEnvironmentPropertySource替换为OriginAwareSystemEnvironmentPropertySource
… 用于追踪不同系统的环境属性org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
… 解析属性名为spring.application.json或SPRING_APPLICATION_JSON的json字符串为Map<String,Object>
… 解析json的工具顺序是:Jackson > Gson > Yaml,以上都没有则使用内置的BasicJsonParser
… 如果系统存在StandardServletEnvironment则将json属性源放在Servlet属性源前面
… 如果系统不存在StandardServletEnvironment则将json属性源放在Environment中第一个位置即优先级最高org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor
… ConfigDataLocationResolver:将location解析成ConfigDataResource
… ConfigDataLoader:通过给定的ConfigDataResource去加载ConfigData
… ConfigDataProperties:记录配置解析过程中额外导入的配置和激活的云平台以及激活的profile
… processInitial:初始处理文件(无activationContext)
… processWithoutProfiles:处理配置数据环境(初始的activationContext)
… processWithProfiles:最后处理配置数据环境(已激活的activationContext)org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
org.springframework.boot.autoconfigure.integration.IntegrationPropertiesEnvironmentPostProcessor
ConfigDataLocationResolver与ConfigDataLoader的实现都是从spring.factories中获取,言外之意就是我们也可以自己定制自己的外部配置数据,
只需要有对应的ConfigDataLoader。如springc-cloud-config中的ConfigServerConfigDataLocationResolver与ConfigServerConfigDataLoader。配置文件一般存放在两个位置:
- 文件目录下,优先级从低到高
- classpath下,优先级从低到高
注意:
- 相同配置项文件目录中的优先级比classpath高
最终Environment中属性源顺序如下图所示:
日志系统
SpringBoot内置三种日志系统:
- LogbackLoggingSystem
- Log4J2LoggingSystem
- JavaLoggingSystem
日志系统的初始化由LoggingApplicationListener完成,有以下5个过程:
ApplicationStartingEvent:应用刚启动时主要为初始化日志系统做准备
… 可以通过配置系统属性org.springframework.boot.logging.LoggingSystem=none关闭日志系统
… 如果org.springframework.boot.logging.LoggingSystem对应的值是继承了抽象类LoggingSystem的className则会使用自实现的日志系统
… 前两种情况一般使用不到,所以系统默认就会从内置的三种日志系统选择一个,这里我们得到的是LogbackLoggingSystem
… 执行beforeInitialize,如果存在SLF4JBridge等依赖,就会把对应的日志全部桥接到统一的日志输出,如:jul-to-slf4jApplicationEnvironmentPreparedEvent:开始初始化日志系统
… 将指定存在于Environment中的配置项(如:编码、样式、级别等)设置到系统属性中(#Why?#)
… 通过配置项logging.file.name或logging.file.path获取日志文件(注意:#同时设置可不是两者的组合#)
… 如果通过logging.config指定了日志的配置文件(如:logback.xml)则会使用指定的配置文件初始化,默认未指定
… 接下来会默认从classpath下查找是否存在logback-test.groovy、logback-test.xml、logback.groovy、logback.xml文件,如果还没有则会将前面四类文件后拼接-spring后继续在classpath下查找即查找logback-test-spring.groovy、logback-test-spring.xml、logback-spring.groovy、logback-spring.xml是否存在(#Why?#)
… 由于我们什么都没配置最后SpringBoot通过编程方式执行默认日志配置初始化(DefaultLogbackConfiguration)完成后并标记已初始化ApplicationPreparedEvent:将日志系统相关对象注册到IOC容器中
… 如果不存在名为springBootLoggingSystem的Bean则把loggingSystem注册到容器中
… 如果配置了日志文件且容器中不存在名为springBootLogFile的Bean则把logFile注册到容器中
… 如果配置了日志组且容器中不存在名为springBootLoggerGroups的Bean则把loggerGroups注册到容器中ContextClosedEvent:发生上下文关闭事件,执行清理流程
… 应用上下文关闭则会清理日志系统,如标记日志系统未初始化等操作ApplicationFailedEvent:应用启动失败,执行清理流程
… SpringBoot应用启动失败也会清理日志系统
加载Starters
主要过程:
加载
… 读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件所有自动配置类,默认有144个
… 通过注解SpringBootApplication中定义的exclude和excludeName以及配置文件中spring.autoconfigure.exclude配置项获取需要排除的自动配置类
… 根据前面核心组件中的<<core.adoc#trueautoconfigurationimportfilter,三个条件接口>>生成ConfigurationClassFilter(同时加载自动配置元数据[845项])用于过滤自动配置类,最终只剩下24项排序
… 首选将自动配置类的before和after注解相关的 #可用类#(存在classpath中)添加到结果集(34项)上
… 接着先按字母顺序自然排序
… 再按指定的自动配置顺序(AutoConfigureOrder,默认0)排
… 最后再根据before和after指定依赖排序
重要:
- #在过滤自动配置类时如果前期没有生成自动配置元数据则不能在此时过滤#
- #要指定自动配置类的配置顺序必须用AutoConfigureOrder不能使用Ordered或者Order注解# . OnClassCondition处理ConditionalOnClass注解
- OnWebApplicationCondition处理ConditionalOnWebApplication注解
- OnBeanCondition处理ConditionalOnBean和ConditionalOnSingleCandidate注解且只是简单判断bean的类型是否存在即class是否存在
元数据生成插件:
spring-boot-autoconfigure-processor:处理自动配类的注解(8个)输出记录在META-INF下spring-autoconfigure-metadata.properties包括条件注解、配置顺序及前后依赖等注解方便后续那来即用不需要实时解析
… org.springframework.boot.autoconfigure.condition.ConditionalOnClass
… org.springframework.boot.autoconfigure.condition.ConditionalOnBean
… org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate
… org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
… org.springframework.boot.autoconfigure.AutoConfigureBefore
…org.springframework.boot.autoconfigure.AutoConfigureAfter
…org.springframework.boot.autoconfigure.AutoConfigureOrder
…org.springframework.boot.autoconfigure.AutoConfigurationspring-boot-configuration-processor:处理自动配置类所依赖的配置属性并输出记录在META-INF下spring-configuration-metadata.json文件中,后续开发时在IDE中就可以提示配置项的类型和默认值(如果有)
SpringBoot2.7 核心源码解读相关推荐
- XXL-JOB核心源码解读及时间轮原理剖析
你好,今天我想和你分享一下XXL-JOB的核心实现.如果你是XXL-JOB的用户,那么你肯定思考过它的实现原理:如果你还未接触过这个产品,那么可以通过本文了解一下. XXL-JOB的架构图(2.0版本 ...
- Airflow核心源码解读
注意:本文基于Airflow 1.10解读源码 Airflow目前已经成为主流的作业调度工具,支持本地调度.分布式调度.Kubernetes调度.Airflow虽然使用Python实现,但功能依然很强 ...
- Java HashMap 核心源码解读
本篇对HashMap实现的源码进行简单的分析. 所使用的HashMap源码的版本信息如下: /* * @(#)HashMap.java 1.73 07/03/13 * * Copyright 2006 ...
- 解密虚拟 DOM——snabbdom 核心源码解读
本文源码地址:https://github.com/zhongdeming428/snabbdom 对很多人而言,虚拟 DOM 都是一个很高大上而且远不可及的专有名词,以前我也这么认为,后来在学习 V ...
- Kafka 核心源码解读【一】--日志模块
文章目录 1 日志段:保存消息文件的对象是怎么实现的? 1.1 Kafka 日志结构概览 1.2 日志段代码解析 1.3 日志段类声明 1.4 append 方法 1.5 read 方法 1.6 re ...
- Kafka 核心源码解读【三】--Controller模块
文章目录 1 Controller元数据:Controller都保存有哪些东西?有几种状态? 1.1 案例分享 1.2 集群元数据 (1)ControllerStats (2)offlineParti ...
- Google Guava之RateLimiter核心源码解读(上)
RateLimiter是Google Guava框架的一个限速器,通常用于控制对某个资源的访问速率. 限速常见的有两种实现方式,一种是令牌桶,另一种是漏桶. RateLimiter选择了令牌桶作为其底 ...
- 新书上市 | Vue 3.0 核心源码解析,这本书给Vue学习提供新方法
Vue.js 作为一款极简的 MVVM 框架,因其轻量.易上手,得到了众多开发者的喜爱. 自从 2014 年 Vue 诞生以来,这个框架设计的初衷,尤大说只是为了设计一个让自己用起来舒服的框架,随着受 ...
- MyBatis核心源码剖析(SqlSession XML解析 Mapper executor SQL执行过程 自定义类型处理器 缓存 日志)
MyBatis核心源码剖析 MyBatis核心源码剖析 1 MyBatis源码概述 1.1 为什么要看MyBatis框架的源码 1.2 如何深入学习MyBatis源码 1.3 源码分析的5大原则 2 ...
最新文章
- SQL Server中遍历表中记录的方法
- 查看mysql数据库服务_MySQL数据库之mysql5.7基础 查看mysql的服务状态
- 多行显示的UIButton
- make 编译可执行
- Java窗口(JFrame)从零开始(8)——文本框+文本域+密码框
- 总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
- 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)
- C++ 类设计核查表
- 数据湖元数据服务的实现和挑战
- css中的背景、边框、补丁相关属性
- 解决ASUS P5GC-MX/1333声卡驱动不能正常安装的问题
- 解决macbook键盘失灵问题
- Android应用: 3D旋转球
- 在Centos8上部署Django环境(Nginx+mysql+uwsgi)
- canvas实现涂鸦效果--橡皮檫和历史记录
- 12306查询车票(爬虫小练_1)
- 通信原理简明教程 | 基本概念
- 简单的数据结构介绍(栈、队列、数组、链表、红黑树)
- [技术发展-28]:信息通信网大全、新的技术形态、信息通信行业高质量发展概览
- WTF是Docker吗?