SpringBoot(二)--SpringBoot启动源码分析

文章目录

  • 入口类
  • SpringApplication实例化
    • 设置应用类型
    • 设置初始化器(Initializer)
    • 设置监听器(Listener)
  • 调用run方法
    • 总体处理流程
    • 源码分析
      • 获取并启动监听器
        • 获取监听器
        • 启动监听器
      • 环境构建
      • 创建容器
      • Spring容器前置处理
      • 刷新容器
      • Spring容器后置处理
      • 发出结束执行的事件
      • 执行Runners

入口类

SpringBoot(二)--SpringBoot启动源码分析_第1张图片

SpringApplication实例化

进入SpringApplication.run(HelloWorldMainApplication.class, args);方法:
SpringBoot(二)--SpringBoot启动源码分析_第2张图片
SpringApplication构造器:
SpringBoot(二)--SpringBoot启动源码分析_第3张图片

设置应用类型

SpringBoot(二)--SpringBoot启动源码分析_第4张图片
引入的依赖中spring-boot-starter-web的配置文件又会引入Tomcat和spring-webmvc.spring-webmvc中存在DispatcherServlet这个类,也就是SpringMVC的核心Servlet,通过类加载能加载DispatcherServlet这个类,那么应用类型自然就是WebApplicationType.SERVLET

设置初始化器(Initializer)

函数getSpringFactoriesInstances( ApplicationContextInitializer.class)
SpringBoot(二)--SpringBoot启动源码分析_第5张图片
loadFactoryNames函数源码:
SpringBoot(二)--SpringBoot启动源码分析_第6张图片
spring-boot-autoconfigure这个包为例,它的META-INF/spring.factories部分定义如下:
SpringBoot(二)--SpringBoot启动源码分析_第7张图片
SharedMetadataReaderFactoryContextInitializerAutoConfigurationReportLoggingInitializer这两个类名被读取出来,然后放入到Set集合(保存的是要加载的类名)中,然后开始实例化操作:
SpringBoot(二)--SpringBoot启动源码分析_第8张图片
初始化器就是org.springframework.context.ApplicationContextInitializer的实现类,这个接口的定义为:
SpringBoot(二)--SpringBoot启动源码分析_第9张图片
在Web应用中,注册Property Sources或者是激活Profiles。Property Sources就是配置文件;Profiles是Spring为了在不同环境下(如DEV、TEST、PRODUCTION等),加载不同的配置项而抽象出来的一个实体。

设置监听器(Listener)

在这里插入图片描述
函数getSpringFactoriesInstances的实现:
SpringBoot(二)--SpringBoot启动源码分析_第10张图片

spring-boot-autoconfigure这个包中的spring.factories中的Key-Value为:
SpringBoot(二)--SpringBoot启动源码分析_第11张图片
这10个监听器会贯穿SpringBoot整个生命周期。到此为止,对于SpringApplication实例的初始化过程就结束了。

调用run方法

总体处理流程

  1. 获取并启动监听器
  2. 根据SpringApplicationRunListeners以及参数来准备环境
  3. 创建Spring容器
  4. Spring容器前置处理
  5. 刷新容器
  6. Spring容器后置处理
  7. 发出结束执行的事件
  8. 执行Runners

源码分析

SpringBoot(二)--SpringBoot启动源码分析_第12张图片
SpringBoot(二)--SpringBoot启动源码分析_第13张图片

获取并启动监听器

获取监听器

SpringBoot(二)--SpringBoot启动源码分析_第14张图片
META-INF/spring.factories中读取Key为org.springframework.boot.SpringApplicationRunListener的Values:
在这里插入图片描述

在函数getSpringFactoriesInstances中利用反射获取实例时会触发EventPublishingRunListener的构造函数,该函数的具体实现为:
SpringBoot(二)--SpringBoot启动源码分析_第15张图片
添加广播器的源码:
该方法定义在SimpleApplicationEventMulticaster父类AbstractApplicationEventMulticaster中。
SpringBoot(二)--SpringBoot启动源码分析_第16张图片
SpringBoot(二)--SpringBoot启动源码分析_第17张图片
综上我们可以看到:EventPublishingRunListener中有一个广播器SimpleApplicationEventMulticaster,广播器SimpleApplicationEventMulticaster中又存放所有的监听器。

启动监听器

通过getRunListeners方法获取的监听器为EventPublishingRunListener该监听器是启动事件发布监听器,主要用来发布启动事件
SpringBoot(二)--SpringBoot启动源码分析_第18张图片
首先来看一下SpringApplicationRunListener这个接口:
SpringBoot(二)--SpringBoot启动源码分析_第19张图片SpringBoot启动时第一个启动事件listeners.starting()
SpringBoot(二)--SpringBoot启动源码分析_第20张图片
继续看SimpleApplicationEventMulticaster的核心方法:
SpringBoot(二)--SpringBoot启动源码分析_第21张图片
这里有四种监听器:
SpringBoot(二)--SpringBoot启动源码分析_第22张图片
以SpringBoot的日志监听器为例,核心代码:因为该事件类型为ApplicationEvent,所以会执行onApplicationStartedEvent((ApplicationStartedEvent) event);SpringBoot会在运行过程中的不同阶段,发送各种事件,来执行对应监听器的对应方法
SpringBoot(二)--SpringBoot启动源码分析_第23张图片

环境构建

在这里插入图片描述
具体实现:
SpringBoot(二)--SpringBoot启动源码分析_第24张图片
SpringBoot(二)--SpringBoot启动源码分析_第25张图片
函数listeners.environmentPrepared(environment);,这里是第二次发布事件,根据事件类型获取到的监听器为:
SpringBoot(二)--SpringBoot启动源码分析_第26张图片
其中的ConfigFileApplicationListener非常核心,主要用来处理项目配置,项目中的propertiesyml文件都是其内部类所加载。
SpringBoot(二)--SpringBoot启动源码分析_第27张图片
首先还是会读spring.factories文件,List postProcessors = loadPostProcessors();获取的处理类有以下四种:
SpringBoot(二)--SpringBoot启动源码分析_第28张图片
在执行完上述三个监听器流程后,ConfigFileApplicationListener会执行该类本身的逻辑,由其内部类Loader加载项目制定路径下的配置文件:
在这里插入图片描述
到此为止,项目的变量配置已全部加载完毕。
SpringBoot(二)--SpringBoot启动源码分析_第29张图片
一共有6个配置文件,取值顺序由上到下。也就是说前面的配置变量会覆盖后面同名的配置变量

创建容器

首先需要了解一下什么是容器?

Spring容器是Spring框架的核心,是用来管理对象的,容器创建对象,把它们连接在一起,配置他们,并管理他们的整个生命周期,从创建到销毁。
在java项目中,使用了org.springframework.context.ApplicationContext接口的实现类;在web项目中,使用了spring.xml—Spring的配置文件(在xml中配置了一系列我们需要的bean,配置之后Spring就会按照我们配置的东西进行解析,从而得到我们需要的值)。
Spring提供了两种不同类型的容器:
BeanFactory容器:它是最简单的容器
ApplicationContext:该容器继承自BeanFactory,包括BeanFactory容器的所有功能。

在这里插入图片描述
具体实现:
SpringBoot(二)--SpringBoot启动源码分析_第30张图片

Spring容器前置处理

这一步主要是在容器刷新之前的准备动作,包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
在这里插入图片描述
具体实现:
SpringBoot(二)--SpringBoot启动源码分析_第31张图片
调用初始化器:
SpringBoot(二)--SpringBoot启动源码分析_第32张图片
我们也可以自定义初始化器,并实现initialize方法,然后放入METAINF/spring.factories配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器就会被调用,是项目初始化的一种方式。
加载启动指定类
在创建SpringApplication实例中,先将HelloWorldMainApplication.class存储在this.primarySources属性中,现在就是用这个属性的时候了,getAllSources()方法的具体实现:
SpringBoot(二)--SpringBoot启动源码分析_第33张图片

函数load(context, sources.toArray(new Object[0]));的具体实现:
SpringBoot(二)--SpringBoot启动源码分析_第34张图片
通知监听器,容器已准备就绪:
在这里插入图片描述
主要还是针对一些日志等监听器的响应处理。

刷新容器

执行到这里,springBoot相关的处理工作已经结束,接下来的工作就交给Spring了,接下来我们来看一下refreshContext(context);函数,该方法是实现IOC和AOP的关键。
SpringBoot(二)--SpringBoot启动源码分析_第35张图片
SpringBoot(二)--SpringBoot启动源码分析_第36张图片
SpringBoot(二)--SpringBoot启动源码分析_第37张图片

Spring容器后置处理

在这里插入图片描述
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法,比如打印一些启动结束log,或者一些其他后置处理。

发出结束执行的事件

SpringBoot(二)--SpringBoot启动源码分析_第38张图片
这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的11个监听器发布启动事件。

执行Runners

函数callRunners(context, applicationArguments);源码:
SpringBoot(二)--SpringBoot启动源码分析_第39张图片
如果是CommandLineRunner的话,执行如下代码:
SpringBoot(二)--SpringBoot启动源码分析_第40张图片
我们也可以自定义一些ApplicationRunner或者CommandLineRunner,实现其run方法,并注入到Spring容器中,在SpringBoot启动完成之后,会执行所有的runnner的run方法。

感谢并参考:
https://www.cnblogs.com/java-chen-hao/p/11829344.html

你可能感兴趣的:(springboot,spring,boot)