springboot启动流程源码解析(带流程图)

7 篇文章 0 订阅
订阅专栏
1 篇文章 0 订阅
订阅专栏

本文自己写的(头条也有这篇文章),若有问题,请指正。

大致流程如下:

1. 初始化SpringApplication,从META-INF下的spring.factories读取
ApplicationListener/ApplicationContextInitializer

2.运行SpringApplication的run方法

3.读取项目中环境变量、jvm配置信息、配置文件信息等

4.创建Spring容器对象(ApplicationContext)

5. 利用
ApplicationContextInitializer初始化Spring容器对象,读取启动类

6.调用spring的refresh加载IOC容器、自动配置类,并创建bean、servlet容器等信息

7.springboot会调用很多监听器

8.如果启动时发生异常,则发送ApplicationFailedEvent事件

下面对上述流程进行源码细化分析,首先调用SpringApplication.run启动springboot应用:

@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@EnableTransactionManagement(proxyTargetClass = true)
@Import(MyDynamicDataSourceConfig.class)
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

进入run方法后,会进行SpringApplication进行启动,分两大步,第一步初始化SpringApplication,第二步调用run方法:

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}

第一步初始化SpringApplication,new SpringApplication(primarySources)的流程如下(具体方法含义参考注释):

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  // 根据classpath下的类,推算当前web应用类型(REACTIVE/SERVLET/NONE)
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
  // 获取BootstrapRegistryInitializer对象,从META-INF/spring.factories中读取key为BootstrapRegistryInitializer,并实例化出对象
 // BootstrapRegistryInitializer的作用是可以初始化BootstrapRegistry
  this.bootstrapRegistryInitializers = new ArrayList<>(
         getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
  //去spring.factories中去获取所有key:org.springframework.context.ApplicationContextInitializer为了初始化Spring容器ApplicationContext对象(可以利用
 //ApplicationContextInitializer向Spring容器中添加ApplicationListener)
  setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  //去spring.factories中去获取所有key: org.springframework.context.ApplicationListener,ApplicationListener是Spring中的监听器
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  //推测main()方法所在的类
   this.mainApplicationClass = deduceMainApplicationClass();
}

第二步调用run方法,初始化完SpringApplication开始运行run方法,源码如下:

public ConfigurableApplicationContext run(String... args) {
   long startTime = System.nanoTime();//记录时间
   //创建DefaultBootstrapContext对象,利用BootstrapRegistryInitializer初始化DefaultBootstrapContext对象
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
  // 开启了Headless模式:
   configureHeadlessProperty();
  //获取SpringApplicationRunListeners, //SpringBoot提供了一个EventPublishingRunListener,它实现了SpringApplicationRunListener接口
  //spring会利用这个类,发布一个ApplicationContextInitializedEvent事件,可以通过定义ApplicationListener来消费这个事件
   SpringApplicationRunListeners listeners = getRunListeners(args);
  // 发布ApplicationStartingEvent事件,在运行开始时发送
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
     // 根据命令行参数 实例化一个ApplicationArguments
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
     // 预初始化环境(见下面的源码分析): 读取环境变量(操作系统的环境变量/JVM的环境变量),读取配置文件信息(基于监听器,会利用EventPublishingRunListener发布一个ApplicationEnvironmentPreparedEvent事件,
		//默认会有一个EnvironmentPostProcessorApplicationListener来处理这个事件,当然也可以通过自定义ApplicationListener来处理这个事件,当ApplicationListener接收到这个事件之后,就会解析application.properties、application.yml文件,
   //并添加到Environment中)
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);// 打印Banner
     //据webApplicationType创建不同的Spring上下文容器(有三种)
      context = createApplicationContext();
      context.setApplicationStartup(this.applicationStartup);
     //预初始化spring上下文,见下面的源码分析
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
     //刷新Spring容器,这一步中创建并初始化bean,创建并启动tomacat等(以tomcat为例,调到ServletWebServerApplicationContext的createWebServer()方法
     //最后执行TomcatServletWebServerFactory的getWebServer方法)
     refreshContext(context);
      afterRefresh(context, applicationArguments);
      Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
      }
     //发布ApplicationStartedEvent事件和AvailabilityChangeEvent事件
      listeners.started(context, timeTakenToStartup);
     // 获取Spring容器中的ApplicationRunner/CommandLineRunner类型的Bean,并执行run方法
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, listeners);//发布ApplicationFailedEvent事件
      throw new IllegalStateException(ex);
   }
   try {
      Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
     //发布ApplicationReadyEvent事件和AvailabilityChangeEvent事件
      listeners.ready(context, timeTakenToReady);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);//发布ApplicationFailedEvent事件
      throw new IllegalStateException(ex);
   }
   return context;
}

预初始化环境,创建Environment对象源码解析:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
   // 根据webApplicationType 创建Environment 创建就会读取: java环境变量和系统环境变量
   ConfigurableEnvironment environment = getOrCreateEnvironment();
  // 将命令行参数读取环境变量中
   configureEnvironment(environment, applicationArguments.getSourceArgs());
  // 将@PropertieSource的配置信息 放在第一位,它的优先级是最低的
   ConfigurationPropertySources.attach(environment);
  // 发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件
   listeners.environmentPrepared(bootstrapContext, environment);
  // 将所有spring.main 开头的配置信息绑定到SpringApplication中
   DefaultPropertiesPropertySource.moveToEnd(environment);
   Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
         "Environment prefix cannot be set via properties.");
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
      environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
   }
   ConfigurationPropertySources.attach(environment);//更新PropertySources
   return environment;
}

预初始化spring上下文源码解析: 

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
   context.setEnvironment(environment);
   postProcessApplicationContext(context);
   applyInitializers(context);// 拿到之前读取到所有ApplicationContextInitializer的组件, 循环调用initialize方法
   listeners.contextPrepared(context);// 发布了ApplicationContextInitializedEvent
   bootstrapContext.close(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }
  // 获取当前spring上下文beanFactory (负责创建bean)
   ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
   beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
   if (printedBanner != null) {
      beanFactory.registerSingleton("springBootBanner", printedBanner);
   }
   if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
      ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
      if (beanFactory instanceof DefaultListableBeanFactory) {
        //在SpringBoot 在这里设置了不允许覆盖, 当出现2个重名的bean 会抛出异常
         ((DefaultListableBeanFactory) beanFactory)
               .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
      }
   }
  // 设置当前spring容器是不是要将所有的bean设置为懒加载
   if (this.lazyInitialization) {
      context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
   }
   context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
   // Load the sources
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
  // 读取主启动类 (因为后续要根据配置类解析配置的所有bean),将启动类作为配置类注册到Spring容器中
   load(context, sources.toArray(new Object[0]));
   listeners.contextLoaded(context);//读取完配置类后发送ApplicationPreparedEvent,默认利用EventPublishingRunListener发布一个ApplicationPreparedEvent事件
}

 

springboot启动流程之bean注册-源码分析(1)
xiaoza7的博客
02-23 732
1,断点进入主程序 2,初始化组件 其中实例化组件时,使用反射,如下示 初始完组建后, 接着是application的run方法 在上面过程中,进入 context = this.createApplicationContext(); 进入,默认创建一个 AnnotationConfigServletWebServerApplicationContext实例 ...
springboot源码解析(一)
qq_34548229的博客
01-03 560
springboot源码解析(一) 1、springboot的入口程序 @SpringBootApplication public class StartupApplication { public static void main(String[] args) { SpringApplication.run(StartupApplication.class, args)...
Springboot 原理 及源码解析
最新发布
Yluciud的博客
08-29 1142
翻译分别为: 目标, 保留, 文档, 继承,可以用于大概猜测注解含义。加在方法或类上,指定该方法在什么条件下才会被注册到Bean的IOC容器中。
SpringBoot一站式启动流程源码分析
Realize My Dream
06-06 204
&#13; &#13; 一、前言&#13;   由上篇文章我们得知,SpringBoot启动时,就是有很简单的一行代码。那我们可以很清楚的看到这行代码的主角便是SpringApplication了,本文我们就来聊一聊这货,来探寻SpringBoot的一站式启动流程。&#13; ​  其实SpringApplication 是将一个典型的Spring应用的启动流程”模板化”了,...
springboot启动流程.rp
06-01
使用Axure画的Springboot启动流程源文件《springboot启动流程.rp》,可以下载编辑。导出的片,请查看博客:https://blog.csdn.net/axin1240101543/article/details/106475798
SpringBoot启动流程源码解析
qq_39839075的博客
02-06 593
SpringBoot启动流程
springboot启动的流程图
qq_42093488的博客
11-20 2724
流程解释 组装SpringApplication 1.resourceLoader:设置resourceload 2.设置primarySources:可以把启动类加载进入spring容器 3.webApplicationType:判断当前application应该运行在什么环境下 4.mainApplicationClass:找出main方法启动的class 执行SpringApp...
可能是全网最全的SpringBoot启动流程源码分析(基于 2.1.5 版本)
01-20
使用 Spring Boot 启动一个微服务十分简单,只需要在启动类上调用 SpringApplication 的run方法即可 点击进入run方法 1 run 静态辅助类,可用于运行使用默认配置(即我们添加的一系列注解)的指定源的 ...
SpringBoot源码SpringBoot内置Tomcat启动流程
xajh_czbk的博客
08-21 715
三、总结一、简介SpringBoot 项目之所以部署简单,其很大一部分原因就是因为不用自己折腾 Tomcat 相关配置,因为其本身内置了各种 Servlet 容器。SpringBoot 是怎么通过简单运行一个 main 函数,就能将容器启动起来,并将自身部署到其上 ,接下来,我们就从源码的角度分析一下SpringBoot启动过程中Tomcat是如果自动启动的。
SpringBoot启动流程源码解析
如切如磋,如琢如磨
12-08 1595
文章目录1 前言2 追本溯源3 容器启动流程3.1 应用启动计时3.2 打印 Banner3.3 创建上下文实例createApplicationContext3.4 构建容器上下文prepareContext3.5 小结 1 前言 在拥有 Spring Boot 以前,我们要运行一个 Java Web 应用,首先需要有一个 Web 容器(例如 Tomcat ),然后将我们的 Web 应用打包后放到容器的相应目录下,最后再启动容器。 在 IDE 中也需要对 Web 容器进行一些配置,才能够运行或者 Deb
详细分析Springboot启动流程
Java技术攻略的博客
03-27 838
本文会对Springboot启动流程进行详细分析。但是请注意,Springboot启动流程Springboot的逻辑,请千万不要将Springboot启动流程相关逻辑与Spring的相关逻辑混在一起,比如把Spring的bean生命周期的逻辑混在Springboot启动流程中,那么整个体系就复杂且混乱了。所以本文仅重点关注Springboot启动流程,涉及Spring的部分,会略作说明并跳过。整体的一个结构如下。Springboot2.4.1Springboot启动时,第一件重要事件就是初始化。
SpringBoot启动流程
01-08
SpringBoot启动流程
Springboot源码流程图
05-07
starter包含了搭建项目快速运行所需的依赖。它是一个依赖关系描述符的集合。当应用需要一种spring的其它服务时,不需要粘贴拷贝大量的依赖关系描述符。例如想在spring中使用redis,只需要在项目中包含 spring-boot-starter-redis 依赖就可以使用了,所有的starters遵循一个相似的命名模式:spring-boot-starter-,在这里是一种特殊类型的应用程序。该命名结构可以帮你找到需要的starter。很多IDEs集成的Maven允许你通过名称搜索依赖。 ———————————————— 版权声明:本文为CSDN博主「weixin_43594111」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_43594111/article/details/105966928
SpringBoot】18张,详解SpringBoot解析yml全流程_springboot解析注册yml文件源码
2301_79099287的博客
05-01 1035
金三银四到了,送上一个小福利!金三银四到了,送上一个小福利![外链片转存中…(img-6Hv0Hosn-1714521004101)][外链片转存中…(img-GVb6J61f-1714521004102)][外链片转存中…(img-KO2NA6tu-1714521004102)]本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录。
SPRING-BOOT启动流程--
esunlang的博客
02-03 3043
Spring-Boot启动流程是一个初问较多的梗故事开篇内容提要本次内容排布第一部分:启动main到initialize第二部分:stopWatch到context功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特功能,丰富你的文章UML 表FLowchart流程图导出与导入导出导入 故事开篇 你好!S
记录学习:springboot 启动流程
weixin_42852915的博客
04-11 846
继承的三个父类接口里,Closeable提供了关闭时资源释放的接口,Lifecycle是提供对生命周期控制的接口(start\stop)以及查询当前运行状态的接口,ApplicationContext则是配置上下文的中心配置接口,继承了其他很多配置接口,其本身提供查询诸如id、应用程序名等上下文档案信息的只读接口,以及构建自动装配bean的工厂。,该方法返回一个可编辑的PropertySources,如果有在启动阶段自定义环境的PropertySources的需求,就可以通过该方法设置。
SpringBootSpringBoot启动源码解析
持续学习,坚持原创,分享技术笔记及经验。
11-12 435
SpringBoot启动源码解析
SpringBoot启动流程源码分析
SpringBoot应用最佳实践
05-29 830
大部分时候,SpringBoot应用主要通过在引导类调用SpringApplication的静态run方法启动,同时将引导类注册为配置源。比如下面是一个SpringMVC的Web应用,引导类是WebMVCBootstrap,和命令行参数args作为SpringApplication静态run方法的参数,用于构建SpringApplication对象和运行SpringBoot应用。 // 引导类添加@SpringBootApplication注解作为配置源,同时开启自动装配、缺省包路径扫描 @Spring
写文章

热门文章

  • springboot启动流程源码解析(带流程图) 4358
  • springboot自动配置原理(详细-带流程图) 2013
  • springboot+mybatisplus+mysql双数据源动态切换(详细版) 1876
  • springmvc执行流程(带图) 1343
  • spring的上下文执行流程(refresh()底层原理及bean扫描流程) 566

分类专栏

  • java 7篇
  • springboot 1篇
  • spring 2篇
  • jvm 1篇

最新评论

  • springboot+mybatisplus+mysql双数据源动态切换(详细版)

    CSDN-Ada助手: 你的文章入选【CSDN 每天最佳新人】,请看:https://bbs.csdn.net/topics/609344083

最新文章

  • nacos1.4.1注册中心源码解析(临时实例AP模式)-含流程图
  • Nacos2.1.0注册中心源码解析-附带全流程图
  • springboot自动配置原理(详细-带流程图)
2022年9篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家玻璃钢雕塑祥云石家庄玻璃钢雕塑句容玻璃钢卡通座椅雕塑梅州会发光的玻璃钢雕塑厂家知名校园玻璃钢雕塑制作厂家南安玻璃钢雕塑厂家伦教仿真玻璃钢人物雕塑巴音郭楞玻璃钢雕塑制造内江玻璃钢雕塑摆件施工价格上海玻璃钢抽象雕塑价格主题玻璃钢人物雕塑哪里买淮南玻璃钢雕塑销售呈贡玻璃钢雕塑加工公司哪家好河南佛像玻璃钢雕塑方法云南公园景观玻璃钢雕塑厂家曲靖玻璃钢雕塑制作芜湖玻璃钢人物雕塑设计广东佛山玻璃钢花盆贵州景区玻璃钢雕塑价位北京多彩玻璃钢雕塑市场陕西定制玻璃钢雕塑销售厂家烟台人物玻璃钢雕塑安装广东走廊商场美陈生产企业莱芜玻璃钢雕塑深圳周年庆典商场美陈批发玻璃钢动物雕塑定制湖南玻璃钢卡通草莓雕塑广东商业商场美陈销售企业黄骅玻璃钢动物雕塑长沙小区玻璃钢雕塑安装香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化