⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 cnblogs.com/insaneXs/p/12721306.html 「insaneXs」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

通过SpringApplication开始引导启动

SpringApplication类是用来执行Spring框架启动的引导类。有两种方式可以进行启动引导:

  1. 通过静态方法SpringApplication.run启动。
  2. 先创建SpringApplication实例,在调用的实例方法run进行启动。

无论是以上哪种方式,最终都是通过创建SpringApplication实例,在调用run()启动。

new SpringApplication——创建引导启动的实例

在创建SpringApplication实例的时候,会根据用户输入和工程环境做一些基础配置,供之后引导启动中使用。

  • 设置ResourceLoader和PrimarySources
  • 从类中加载initializer和listener放在集合
  • 设置是否为Web环境(先确认用户是否指定,未指定则根据工程目录下是否有servlet相关环境)
  • 从工程环境中决定主入口的类

run()——开始引导启动

new StopWatch()——创建计时器

StopWatchspringframework.util中提供的一个工具类,在启动过程中使用StopWatch是为了记录启动花费的时间。

configureHeadlessProperty()——配置Headless模式

Headless模式是在环境缺少显示器等设备情况下的一种配置,和我们启动流程并无太多关系,不做介绍。

SpringApplicationRunListener.start()——获取监听器,启动监听

监听器可以用来监听SpringApplication启动过程中的各个阶段。默认的监听器是EventPublishRunListener,用户也可以通过实现SpringApplicationRunListener接口,实现应用程序对SpringApplication启动过程的监听。

在 resources/META-INF 下建立 spring.factories 文件,文件中添加 key=value 形式,其中 key 为 SpringApplicationRunListener 的全路径名,value 为应用程序对该接口的实现类(类需要一个参数类型为 SpringApplication 和 String 数组的构造函数,用于通过反射创建实例)。

prepareEnvironment()——准备环境,创建ConfigurableEnvironment对象

在这一步,SpringApplication会创建Spring启动所需的环境,这个环境主要由ConfigurableEnviroment对象表示。首先,该对象确认了程序是否需要设置Web环境,其次,该对象还确定了程序所需要的参数和读取的配置文件等信息。

此步骤会回调SpringApplicationRunListenerenvironmentPrepared()方法,通知监听器环境已经准备好。

printBanner()——打印横幅

这一步骤其实和启动并没有太大关系,只是会向控制台或是日志中输出Spring的Logo和版本信息。

createApplicationContext()——创建应用程序上下文并加载Bean

在准备好环境之后,接下来要做的就是创建应用程序上下文ApplicationContext对象。 ApplicationContext是Spring IoC的核心组件,它不仅是程序所需Bean的容器,还提供了国际化,事件发布等功能。

在创建应用程序上下文的时候,首先会根据之前配置决定上下文的具体类型(AnnotationConfigApplicationContext或是AnnotationConfigServletWebServerApplicationContext)。 再通过反射实例化到对象。

prepareContext()——准备ApplicationContext

虽然已经得到了ApplicationContext对象,但此时的对象还只是一个空白对象,需要准备和处理后,ApplicationContext才能被使用。

在准备过程中主要做了做了几件事: 为ApplicationContext设置之前准备好的Environment对象。

通过对ApplicationContext后置处理或是BeanDefinitionLoader等方式往容器中添加一些初始的Bean。

应用默认的初始化器初始化应用程序上下文(责任链模式的应用,多个初始化器形成一个List,应用程序需要被每个初始化器应用一次,每个初始化器有自己的职责)。

准备过程中ApplicationRunListener发出两个消息,分别是contextPreparedcontextLoaded

refreshContext()——刷新上下文

在应用程序上下文准备好后,可以通过刷新应用程序上下文发现Bean并加载到容器中。 refreshContext()会调用ApplicationContext.refresh()方法。

AbstractApplicationContext中定义了refresh()方法的基本框架(模板模式的应用)。

prepareRefresh()——准备刷新

准备刷新的阶段做了初始化和校验的工作。比如初始化启动时间,初始化PropertySources(在AbstractApplicationContext中只是一个空方法,留给子类根据需要实现),以及校验环境中是否已经有必要的参数。

prepareBeanFactory()——准备BeanFactory

BeanFactory是 Spring 框架中容器的底层实现,所有的 Bean 都存放在BeanFactory中,虽然ApplicationContext也实现了BeanFactory接口,但是在其内部还是将获取 Bean 的相关操作委托给内部的DefaultListableBeanFactory变量,只是ApplicationContext帮用户屏蔽了底层的操作,同时提供出一些更符合外部用户使用的接口。

对BeanFactory的准备主要是: 添加一些必要组件,比如类加载器,表达式解析器,属性编辑器注册表等。

以及一些后置处理器,比如ApplicationContextAwareProcessor(xxxAware的接口就是通过后置处理器在Bean创建的时候,通过后置处理器设置的)。 此外还有一些特殊的Bean,environment,systemPropertiessystemEnvirnoment

postProcessBeanFactory()——后置处理BeanFactory

对于非WebServlet环境的ApplicationContext而言这个方法是个空方法,但是Web环境下的ApplicationContext会通过这个方法定制一些后处理动作,比如添加WebApplicationContextServletAwareProcessor后置处理器,添加在web环境中可能使用的Scope(sessionrequest)。

invokeBeanFactoryPostProcessors()——实例化并调用BeanFactoryPostProcessor

BeanFactoryPostProcessor是一种特殊的后置处理器,其操作的对象是针对BeanFactory。 此时主要有三个后置处理器,分别是:SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor,ConfigurationWarningsApplicationContextInitializer$ConfigurationWarningsPostProcessorConfigFileApplicationListener$PropertySourceOrderingPostProcessor。这三个类名字虽然很长,但是其实是因为内部类的关系,而且我们看名字也能发现类是怎么来的(外部类是xxxInitializer的就说明是初始化器设置的)。

其中第一个类和启动流程有关,因为它会向容器注册ConfigurationClassPostProcessor

如果BeanFactoryPostProcessor同时又是BeanDefinitionRegistryPostProcessor,则先进行针对BeanDefinition注册表的后置处理,目的是为了发现Bean。 在最初的三个BeanFactoryProcessor后置处理完成后,会从容器中获取BeanDefinitionRegistryPostProcessor类型的后置处理器(这里主要会得到刚才加载的ConfigurationClassPostProcessor实例)。再调用这些BeanDefinitionRegistry的后置处理器,继续向发现并向容器中注册新的Bean。

这里主要是通过@Configuration注解作为入口发现Bean,如果发现的Bean中又存在新的@ConfigurationBean,则以此Bean为入口再进行发现,直到所有的Bean都被发现。

在针对BeanDefinition注册表的后置处理完成(发现Bean的过程)中,如果找到了BeanFactoryPostProcessor(包括最初的三个BeanFatoryProcessor),会进行针对BeanFactory的后置处理过程(之前只是进行针对注册表的后置处理,二者的目的还是有区别的)。

注意 Bean的发现过程只是向BeanDefinition注册表注册BeanDefinition的过程,并没有针对发现的Bean进行实例化(少部分需要用到的Bean会进行实例化,比如这部分会对BeanDefinitionRegistryPostProcessor类型的Bean实例化)。

registerBeanPostProcessors()——注册Bean后置处理器

上一步是针对BeanFactoryBeanDefinitionRegistry的后置处理器,这一步从BeanFactory中获取针对普通Bean的后置处理器BeanFactoryPostProcessor放到专门的容器beanPostProcessors中。

initMessageSource()——初始化MessageSource

MessageSource是拥有特殊功能的Bean,用来处理国际化相关内容。

initApplicationEventMulticaster()——初始化ApplicationEventMulticaster

ApplicationEventMulticaster是ApplicationEvent广播器,可以通过这个对象向容器中添加移除Listener,也可以通过这个对象发布事件(观察者模式的应用)。

onRefresh()——刷新应用程序

发现了所有的Bean,并且需要实例化的Bean也都被创建好了之后,Spring接下去要做的是创建ThemeSource(和主题相关的组件),以及创建Webserver(如果是Web环境的话)。

registerListeners()——注册监听器

这一步会将初始化得到的ApplicationListener方法和容器中获得ApplicationListener一起注册到ApplicationEventMulticaster中,并且如果存在需要早起发布的事件,则发布事件。

finishBeanFactoryInitialzation()——初始化容器中的Bean

经过之前的步骤,现在容器中必要的组件都已经准备好了,并且所有需要容器管理的Bean也都已经被发现注册成BeanDefinition注册表中。 对于Scope是Singleton的Bean而言,此时已经具备了实例化Bean的条件,因此在这一步中,Spring会对所有Singleton且非lazy-init的Bean进行实例化。 主要做法就是获取容器中所有为singletion且非lazyInit的BeanDefinition,然后通过getBean创建出Bean的实例,保存在容器内部。

有一种特殊的情况是针对FactoryBean,FactoryBean是一种用来创建Bean的特殊Bean,在得到FactoryBean的Bean之后,还需要判断是否要创建FactoryBean负责创建的Bean。

Bean的实例化过程getBean()再以后的文章中再介绍。

finishRefresh()——完成刷新

在这步主要是一些资源清理以及注册LifeCycleProcessorLifeCycleProcessor可以用来在 Spring 生命周期的refreshclose时触发回调。 并且发布Refresh的消息。

afterRefresh()——留给子类的钩子函数

在Application完成刷新后,SpringApplication给子类留了afterRefresh()的方法作为回调。

启动完成

启动完成后,stopWatch会记录下本次启动消费的时间。 然后向ApplicationRunListener发布started事件,说明已经启动就绪。

准备运行

启动完成后,正式运行前,SpringApplication还会执行用户定义的ApplicationRunnerCommandLineRunner两个接口中定义的run()方法。 在执行完成后,向ApplicationRunListener发布runing的消息。 至此,启动流程结束。

总结

本文旨在对SpringBoot启动流程各个步骤做一次梳理(本文的段落标题就是启动的各个步骤,不同等级的标题也含有方法前后调用的关系),并没有对每行代码做深入分析。如果感兴趣的读者可以对照流程自己分析一遍。

文章目录
  1. 1. 通过SpringApplication开始引导启动
  2. 2. new SpringApplication——创建引导启动的实例
  3. 3. run()——开始引导启动
    1. 3.1. new StopWatch()——创建计时器
    2. 3.2. configureHeadlessProperty()——配置Headless模式
    3. 3.3. SpringApplicationRunListener.start()——获取监听器,启动监听
    4. 3.4. prepareEnvironment()——准备环境,创建ConfigurableEnvironment对象
    5. 3.5. printBanner()——打印横幅
    6. 3.6. createApplicationContext()——创建应用程序上下文并加载Bean
    7. 3.7. prepareContext()——准备ApplicationContext
    8. 3.8. refreshContext()——刷新上下文
      1. 3.8.1. prepareRefresh()——准备刷新
      2. 3.8.2. prepareBeanFactory()——准备BeanFactory
      3. 3.8.3. postProcessBeanFactory()——后置处理BeanFactory
      4. 3.8.4. invokeBeanFactoryPostProcessors()——实例化并调用BeanFactoryPostProcessor
      5. 3.8.5. registerBeanPostProcessors()——注册Bean后置处理器
      6. 3.8.6. initMessageSource()——初始化MessageSource
      7. 3.8.7. initApplicationEventMulticaster()——初始化ApplicationEventMulticaster
      8. 3.8.8. onRefresh()——刷新应用程序
      9. 3.8.9. registerListeners()——注册监听器
      10. 3.8.10. finishBeanFactoryInitialzation()——初始化容器中的Bean
      11. 3.8.11. finishRefresh()——完成刷新
    9. 3.9. afterRefresh()——留给子类的钩子函数
    10. 3.10. 启动完成
    11. 3.11. 准备运行
  4. 4. 总结