写代码啦
SpringBoot启动详解
回复数(1) 浏览数(105)
树知知 03月21日 20:15 最后回复来自: 可一可再 学霸评比参赛博客
{{topic.upvote_count || 0}} 编辑 回复

在使用SpringBoot框架时,这些简便又实用的功能得以让开发效率极高;那SpringBoot的这些功能在背后如何实现的呢?

一般肯定都会说DI和IOC,这些Spring的核心功能;但今天我们来看一看SpringBoot它启动的整个过程,看完你会不由自主的来一句“原来如此”!!

:fire:总览

下图是SpringBoot启动的整个过程缩略图:

springboot启动过程.png springboot启动过程.png

​ 在图中,可以看出来启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块主要使用到SpringFactoriesLoader(Spring工厂加载器),主要功能是对传入的factoryClass和ClassLoader进行装配和实现(通过反射获取类对象和构造方法生成实例)。


:runner:启动

​ 在Java中程序的主要入口都是通过main函数,SpringBoot也不例外(因为它其实也只是一段Java程序而已);所以在main方法中来进行调用SpringApplication.run(application.class,args)启动SpringBoot程序;当然不是任何一个类主方法都可以去启动SpringApplication,肯定是有要求的!

:loudspeaker: 首先该方法所在类需要使用@SpringBootApplication注解,以及@ImportResource(if need)注解;为何一个@SpringBootApplication注解这么厉害,就能搞定这么多,进去一探究竟

:flashlight: @SpringBootApplication 其中包含如下注解,主要的是

  • @SpringBootConfiguration: 被标注的类等于在spring的XML配置文件中(applicationContext.xml),装配所有bean事务,提供了一个spring的上下文环境
  • @EnableAutoConfiguration: SpringBoot根据应用所声明的依赖来对Spring框架进行自动配置
  • @ComponentScan: 组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Application.class所在的包路径下文件,所以最好将该启动类放到根包路径下

@SPringBootApplication.png @SPringBootApplication.png

SpringBoot启动类

在main函数内调用SpringApplication.run方法,会来到SpringApplication.java文件中,执行run方法;

springrun.png springrun.png

在run方法调用前,会先去初始化SpringApplication,可以看见如下过程,主要是判断

  • 主要资源是否为空,为空就报错;不为空就将其存进LinkedHashSet中
  • 配置是否为web环境: WebApplicationType有3个枚举类型:
    • NONE :不是web应用
    • SERVLET : 以嵌入Servlet启动web应用
    • REACTIVE :以响应式嵌入web应用
  • 创建初始化构造器 -> 获取Spring工厂实例
  • 创建应用监听器
  • 配置应用的主方法所在类

SpringApplication.png SpringApplication.png

:bicyclist: SpringBootApplication启动应用步骤

前面将SpringApplication的基本所需环境已经初始化配置好后就会进入到Application的run方法里面;这里就是SpringApplication具体去管理和实现你项目中所依赖的Bean,从而让整个程序运行起来并保障功能正常。

整体步骤

整个启动应用步骤大致也可以分为4个部分:

  • 首先启动计时器、监听器并进行监听,其中包括监听模块的启动、监听配置环境、应用上下文等等
  • 配置环境模块,创建配置环境(wev/noweb)、加载属性文件资源、配置监听
  • Banner配置,这算是一个SpringBoot的彩蛋,因为启动时打印的Spring字符串就在默认的Banner里面
  • 应用上下文模块,包括创建应用上下文的对象、基本属性的配置(加载配置环境、资源加载器、配置监听)、更新应用上下文(我们项目中所依赖的的Bean的实例化就是在这里进行的,通过工厂产生环境所需的Bean)、应用启动计时器和监听器都结束、callRunner会调用CommandLineRunner,如果对CommandLineRunner进行了如下配置会在终端窗口打印出Bean的名称;到这里SpringApplication的启动就完成了,告一段落了。

  • commandline.png commandline.png

run.png run.png

:mag_right: 关键步骤

  1. 创建应用的监听器SpringApplicationRunListeners并启动,主要对启动过程中的操作进行监听,通过SPringFactory进行创建的监听实例

  2. 加载SpringBoot配置环境(ConfigurableEnvironment),在prepareEnvironment中,getOrCreatEnvironment进行判断加载的应用类型,如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment, 类图如下

stand.png stand.png

可以看出,Environment最终都实现了PropertyResolver接口,我们平时通过environment对象获取配置文件中指定Key对应的value方法时,就是调用了propertyResolver接口的getProperty方法 

prepareContext.png prepareContext.png

  1. 配置环境(Environment)加入到监听器对象中(SpringApplicationRunListeners)

  2. 创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文),我们可以看一下创建方法:

creatApplication.png creatApplication.png

方法会先获取显式设置的应用上下文(applicationContextClass),如果不存在,再加载默认的环境配置(通过是否是web Environment判断),默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载Bean),最后通过BeanUtils实例化上下文对象,并返回,ConfigurableApplicationContext继承类图如下:

context.png context.png

主要看其继承的两个方向:

LifeCycle:生命周期类,定义了start启动、stop结束、isRunning是否运行中等生命周期空值方法

ApplicationContext:应用上下文类,其主要继承了beanFactory(bean的工厂类)

  1. 在prepareContext中主要是将 listeners、environment、applicationArguments、banner等重要组件与上下文对象关联

  2. 接下来的refreshContext(context)方法(初始化方法如下)将是实现spring-boot-starter-*(mybatis、redis等)自动化配置的关键,包括spring.factories的加载,bean的实例化等核心工作。

refresh.png refresh.png

配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成 。

:postbox: 自动化配置

在之前的启动结构图中,可以看到无论是应用的初始化还是具体的执行过程,都调用了SpringBoot自动配置模块。

自动化配置.png 自动化配置.png

该配置模块的主要使用到了SpringFactoriesLoader,即Spring工厂加载器,该对象提供了loadFactoryNames方法,入参为factoryClass和classLoader,即需要传入上图中的工厂类名称和对应的类加载器,方法会根据指定的classLoader,加载该类加器搜索路径下的指定文件,即spring.factories文件,传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类。

获取到这些实现类的类名后,loadFactoryNames方法返回类名集合,方法调用方得到这些集合后,再通过反射获取这些类的类对象、构造方法,最终生成实例

mybatis-spring-boot-starter、spring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。

{{topic.upvote_count || 0}}

在使用SpringBoot框架时,这些简便又实用的功能得以让开发效率极高;那SpringBoot的这些功能在背后如何实现的呢?

一般肯定都会说DI和IOC,这些Spring的核心功能;但今天我们来看一看SpringBoot它启动的整个过程,看完你会不由自主的来一句“原来如此”!!

:fire:总览

下图是SpringBoot启动的整个过程缩略图:

springboot启动过程.png springboot启动过程.png

​ 在图中,可以看出来启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块主要使用到SpringFactoriesLoader(Spring工厂加载器),主要功能是对传入的factoryClass和ClassLoader进行装配和实现(通过反射获取类对象和构造方法生成实例)。


:runner:启动

​ 在Java中程序的主要入口都是通过main函数,SpringBoot也不例外(因为它其实也只是一段Java程序而已);所以在main方法中来进行调用SpringApplication.run(application.class,args)启动SpringBoot程序;当然不是任何一个类主方法都可以去启动SpringApplication,肯定是有要求的!

:loudspeaker: 首先该方法所在类需要使用@SpringBootApplication注解,以及@ImportResource(if need)注解;为何一个@SpringBootApplication注解这么厉害,就能搞定这么多,进去一探究竟

:flashlight: @SpringBootApplication 其中包含如下注解,主要的是

  • @SpringBootConfiguration: 被标注的类等于在spring的XML配置文件中(applicationContext.xml),装配所有bean事务,提供了一个spring的上下文环境
  • @EnableAutoConfiguration: SpringBoot根据应用所声明的依赖来对Spring框架进行自动配置
  • @ComponentScan: 组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Application.class所在的包路径下文件,所以最好将该启动类放到根包路径下

@SPringBootApplication.png @SPringBootApplication.png

SpringBoot启动类

在main函数内调用SpringApplication.run方法,会来到SpringApplication.java文件中,执行run方法;

springrun.png springrun.png

在run方法调用前,会先去初始化SpringApplication,可以看见如下过程,主要是判断

  • 主要资源是否为空,为空就报错;不为空就将其存进LinkedHashSet中
  • 配置是否为web环境: WebApplicationType有3个枚举类型:
    • NONE :不是web应用
    • SERVLET : 以嵌入Servlet启动web应用
    • REACTIVE :以响应式嵌入web应用
  • 创建初始化构造器 -> 获取Spring工厂实例
  • 创建应用监听器
  • 配置应用的主方法所在类

SpringApplication.png SpringApplication.png

:bicyclist: SpringBootApplication启动应用步骤

前面将SpringApplication的基本所需环境已经初始化配置好后就会进入到Application的run方法里面;这里就是SpringApplication具体去管理和实现你项目中所依赖的Bean,从而让整个程序运行起来并保障功能正常。

整体步骤

整个启动应用步骤大致也可以分为4个部分:

  • 首先启动计时器、监听器并进行监听,其中包括监听模块的启动、监听配置环境、应用上下文等等
  • 配置环境模块,创建配置环境(wev/noweb)、加载属性文件资源、配置监听
  • Banner配置,这算是一个SpringBoot的彩蛋,因为启动时打印的Spring字符串就在默认的Banner里面
  • 应用上下文模块,包括创建应用上下文的对象、基本属性的配置(加载配置环境、资源加载器、配置监听)、更新应用上下文(我们项目中所依赖的的Bean的实例化就是在这里进行的,通过工厂产生环境所需的Bean)、应用启动计时器和监听器都结束、callRunner会调用CommandLineRunner,如果对CommandLineRunner进行了如下配置会在终端窗口打印出Bean的名称;到这里SpringApplication的启动就完成了,告一段落了。

  • commandline.png commandline.png

run.png run.png

:mag_right: 关键步骤

  1. 创建应用的监听器SpringApplicationRunListeners并启动,主要对启动过程中的操作进行监听,通过SPringFactory进行创建的监听实例

  2. 加载SpringBoot配置环境(ConfigurableEnvironment),在prepareEnvironment中,getOrCreatEnvironment进行判断加载的应用类型,如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment, 类图如下

stand.png stand.png

可以看出,Environment最终都实现了PropertyResolver接口,我们平时通过environment对象获取配置文件中指定Key对应的value方法时,就是调用了propertyResolver接口的getProperty方法 

prepareContext.png prepareContext.png

  1. 配置环境(Environment)加入到监听器对象中(SpringApplicationRunListeners)

  2. 创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文),我们可以看一下创建方法:

creatApplication.png creatApplication.png

方法会先获取显式设置的应用上下文(applicationContextClass),如果不存在,再加载默认的环境配置(通过是否是web Environment判断),默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载Bean),最后通过BeanUtils实例化上下文对象,并返回,ConfigurableApplicationContext继承类图如下:

context.png context.png

主要看其继承的两个方向:

LifeCycle:生命周期类,定义了start启动、stop结束、isRunning是否运行中等生命周期空值方法

ApplicationContext:应用上下文类,其主要继承了beanFactory(bean的工厂类)

  1. 在prepareContext中主要是将 listeners、environment、applicationArguments、banner等重要组件与上下文对象关联

  2. 接下来的refreshContext(context)方法(初始化方法如下)将是实现spring-boot-starter-*(mybatis、redis等)自动化配置的关键,包括spring.factories的加载,bean的实例化等核心工作。

refresh.png refresh.png

配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成 。

:postbox: 自动化配置

在之前的启动结构图中,可以看到无论是应用的初始化还是具体的执行过程,都调用了SpringBoot自动配置模块。

自动化配置.png 自动化配置.png

该配置模块的主要使用到了SpringFactoriesLoader,即Spring工厂加载器,该对象提供了loadFactoryNames方法,入参为factoryClass和classLoader,即需要传入上图中的工厂类名称和对应的类加载器,方法会根据指定的classLoader,加载该类加器搜索路径下的指定文件,即spring.factories文件,传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类。

获取到这些实现类的类名后,loadFactoryNames方法返回类名集合,方法调用方得到这些集合后,再通过反射获取这些类的类对象、构造方法,最终生成实例

mybatis-spring-boot-starter、spring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。

105
回复 编辑