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

07、SpringBoot 源码分析 - SpringApplication启动流程七

SpringBoot 源码分析 - SpringApplication启动流程七

  • 初始化基本流程
  • SpringApplication的prepareContext准备上下文
    • postProcessApplicationContext处理
    • applyInitializers初始化器初始化
    • load
  • SpringApplication的refreshContext刷新上下文
    • refresh
      • ServletWebServerApplicationContext的refresh

初始化基本流程

在这里插入图片描述

SpringApplication的prepareContext准备上下文

这里面有干了很多事,他会将最前面获得的初始化器都初始化,然后广播上下文准备好事件,然后这里居然还设置了不能覆盖同名bean定义,这样就避免了用户去捣乱了。最后会把启动类的注册到bean定义里,然后广播上下文加载完成事件。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {context.setEnvironment(environment);//配置环境postProcessApplicationContext(context);//一些设置处理applyInitializers(context);//初始化监听器进行初始化listeners.contextPrepared(context);//广播上下文准备好的事件ApplicationContextInitializedEventif (this.logStartupInfo) {//控制台打启动信息logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beansConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory)//不允许同名的bean定义的覆盖.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}// Load the sourcesSet<Object> sources = getAllSources();//获取启动源集合,就是传给SpringApplication的参数类Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));//注册启动类的bean定义listeners.contextLoaded(context);//广播上下文加载完成事件ApplicationPreparedEvent}

postProcessApplicationContext处理

就是提前去注册bean名字生成器,资源加载器,还有前面创建的转换器也要放进来。

	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {if (this.beanNameGenerator != null) {context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,this.beanNameGenerator);}if (this.resourceLoader != null) {if (context instanceof GenericApplicationContext) {((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);}if (context instanceof DefaultResourceLoader) {((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());}}if (this.addConversionService) {//添加转换器context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());}}

applyInitializers初始化器初始化

获取最开始创建的初始化器,遍历每一个初始化器,进行初始化。

	protected void applyInitializers(ConfigurableApplicationContext context) {for (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);//获取ApplicationContextInitializer接口的泛型类型Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");//context不是requiredType类型是不行的initializer.initialize(context);//初始化}}

load

创建bean定义加载器,进行bean定义的加载,就是把sources注册到bean定义里。

protected void load(ApplicationContext context, Object[] sources) {if (logger.isDebugEnabled()) {logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));}BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);if (this.beanNameGenerator != null) {loader.setBeanNameGenerator(this.beanNameGenerator);}if (this.resourceLoader != null) {loader.setResourceLoader(this.resourceLoader);}if (this.environment != null) {loader.setEnvironment(this.environment);}loader.load();}//遍历每一个加载int load() {int count = 0;for (Object source : this.sources) {count += load(source);}return count;}

根据不同类型加载,最后都是registerBean
在这里插入图片描述

SpringApplication的refreshContext刷新上下文

除了刷新外,还注册了一个钩子

	private void refreshContext(ConfigurableApplicationContext context) {refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}

refresh

调用当前上下文AbstractApplicationContext类型的refresh,当前上下文是ServletWebServerApplicationContext类型的,所以会调用到他的refresh

	protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();}

ServletWebServerApplicationContext的refresh

然后他又调用父类的refresh

	@Overridepublic final void refresh() throws BeansException, IllegalStateException {try {super.refresh();}catch (RuntimeException ex) {stopAndReleaseWebServer();throw ex;}}

里面就是springrefresh方法,进行初始化,就不讲了,可以看我写的spring源码文章,其实内部干了不少事情,后面会讲,毕竟前面那么多初始化器初始化了,肯定会对后面spring初始化有所作用。
看看钩子方法,其实就是注册一个关闭线程:
在这里插入图片描述

刷新完成后基本没啥事了,就进行启动完成事件通知,还有一些的ApplicationRunnerCommandLineRunner类型的bean要处理,一般是没有的:
在这里插入图片描述
最后再通知一个运行事件初始化就完成了:
在这里插入图片描述

相关文章:

  • 入门五(项目介绍及登录和发布需求)
  • k8s 创建 LoadBalancer 类型的 svc
  • python数据分析-CO2排放分析
  • 安卓开发--安卓使用Echatrs绘制折线图
  • 二.对配置文件中数据库密码进行加密
  • Java 为什么使用泛型
  • Linux程序开发(十二):线程与多线程同步互斥实现抢票系统
  • 【单片机】STM32F070F6P6 开发指南(一)STM32建立HAL工程
  • VUE2 tab切换导航 展示页面内容(父级子级独立)
  • c语言:模拟strlen(三种方法)最全版本
  • Day03—flask与react实现交互(解决跨域问题)
  • 从容应对亿级QPS访问,Redis还缺少什么?no.29
  • c语言----函数
  • 中间件的概念及示例
  • Android跨进程通信--Binder机制及AIDL是什么?
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 2017 年终总结 —— 在路上
  • ECMAScript入门(七)--Module语法
  • Java面向对象及其三大特征
  • Linux Process Manage
  • Object.assign方法不能实现深复制
  • Python_OOP
  • Python中eval与exec的使用及区别
  • Spark学习笔记之相关记录
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • 翻译:Hystrix - How To Use
  • 关于使用markdown的方法(引自CSDN教程)
  • 后端_ThinkPHP5
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 如何设计一个比特币钱包服务
  • 如何实现 font-size 的响应式
  • 少走弯路,给Java 1~5 年程序员的建议
  • 思考 CSS 架构
  • 项目实战-Api的解决方案
  • #NOIP 2014# day.2 T2 寻找道路
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #微信小程序:微信小程序常见的配置传值
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (31)对象的克隆
  • (52)只出现一次的数字III
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • *算法训练(leetcode)第四十天 | 647. 回文子串、516. 最长回文子序列
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET_WebForm_layui控件使用及与webform联合使用
  • .NET框架
  • .net连接oracle数据库
  • .NET使用存储过程实现对数据库的增删改查
  • .Net转Java自学之路—基础巩固篇十三(集合)
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • @component注解的分类