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

Springboot启动过程详解

一、Springboot

简介

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。

Spring Boot 是一个开源的 Java 框架,用于简化 Spring 应用程序的开发。它是 Spring 生态系统的一部分,旨在帮助开发人员更快速和方便地创建独立、生产级的 Spring 应用。

Spring Boot 是一个强大的框架,极大地简化了 Spring 应用的开发过程,特别适合构建微服务和 RESTful API。

主要特点

  • 快速入门:Spring Boot 通过约定优于配置的原则,使开发者可以快速上手,无需繁琐的 XML 配置。

  • 自带嵌入式服务器:Spring Boot 支持嵌入式服务器(如 Tomcat、Jetty 和 Undertow),开发者无需单独部署应用服务器,可以直接运行 Java 应用。

  • 自动配置:Spring Boot 提供了自动配置功能,根据项目的类路径和配置自动设置 Spring 应用的各种组件,减少了大量的配置工作。

  • 生产级特性:Spring Boot 内置了许多生产环境所需的功能,如健康检查、指标监控、应用配置管理等。

  • 开箱即用:Spring Boot 提供了一系列的 starter 依赖,简化了依赖管理。例如,spring-boot-starter-web 可以帮助快速构建基于 Spring MVC 的 web 应用。

  • 支持微服务架构:Spring Boot 适合构建微服务应用,结合 Spring Cloud,能够实现分布式系统的开发。

核心概念

  • 启动器(Starters):启动器是一组方便的依赖描述符,允许用户在构建时快速引入常用的库。例如:

    • spring-boot-starter-data-jpa:用于与 JPA 数据库交互。
    • spring-boot-starter-web:用于构建 Web 应用。
  • 自动配置类:Spring Boot 中的 @EnableAutoConfiguration 注解可以启用自动配置,开发者可以通过 @Configuration 注解创建自定义配置。

  • 应用配置:Spring Boot 使用 application.properties 或 application.yml 文件来集中管理应用配置。支持不同环境的配置(如开发、测试、生产)通过文件名后缀进行管理。

  • 命令行界面(CLI):Spring Boot 提供命令行界面,支持快速创建和测试 Spring 应用。

二、启动流程

1.@SpringBootApplication注解

众所周知,在 SpringBoot 启动类上都少不了@SpringBootApplication注解。可以肯定的是,所有的标准的springboot的应用程序都是从run方法开始的。

每个Spring Boot应用程序都包含一个 main 方法,这是程序的入口,也是 JVM 启动的切入点。常见的 main 方法例子如下:

@SpringBootApplication
public class MainApplication {public static void main(String[] args) {SpringApplication.run(MainApplication.class, args);}
}

查看@SpringBootApplication注解源码如下,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)Class<?>[] exclude() default {};@AliasFor(annotation = EnableAutoConfiguration.class)String[] excludeName() default {};@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")String[] scanBasePackages() default {};@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")Class<?>[] scanBasePackageClasses() default {};@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;@AliasFor(annotation = Configuration.class)boolean proxyBeanMethods() default true;

可以看到,其核心使用了@SpringBootConfiguration 和 @EnableAutoConfiguration,前者的作用类似于 @Configuration 表明是一个Java 配置类。而@EnableAutoConfiguration 则是将所有符合配置条件的 Bean 都加载到 IOC 容器中。

2.SpringApplication.run() 方法

接下来是调用SpringApplication.run() 方法启动整个Spring Boot程序。

让我们深入了解一下SpringApplication.run的内部工作原理。这个方法首先创建了一个SpringApplication对象,然后调用了run方法。 

SpringApplication.run(MyApplication.class, args)实际上执行了多步操作。这行代码主要做了以下事情:

  1. 创建 SpringApplication 实例。
  2. 配置 SpringApplication(应用启动前的一些准备工作)。
  3. 运行该实例。

3.SpringApplication 实例创建

在 SpringApplication 的构造方法中,进行了一些初始化操作:

  1. 确定应用程序的类型(是 Servlet 应用还是 Reactive 应用)。
  2. 初始化应用上下文(ApplicationContext)。
  3. 读取和存储初始的运行监听器(SpringApplicationRunListeners)。
  4. 初始化应用程序引导程序(ApplicationContextInitializers)。

确定应用程序类型

在SpringApplication的构造方法内,首先会通过 WebApplicationType.deduceFromClasspath()方法来进行 Web 应用类型的推断。判断当前应用程序的容器默认使用的是Servlet 容器,除了servlet之外,还有NONE 和 REACTIVE (响应式编程)

其中,WebApplicationType是一个枚举类, 它定义了可能的 Web 应用类型,该枚举类提供了三类定义:枚举类型、推断类型的方法和用于推断的常量。枚举类型包括非 Web 应用、基于 SERVLET 的 Web 应用和基于 REACTIVE 的 Web 应用,代码如下。

WebApplicationType内针对Web应用类型提供了两个推断方法:deduceFromClasspath 方法和
deduceFromApplicationContext 方法。

那我们就进入WebApplicationType.deduceFromClasspath()方法,下面重点分析该方法的实现。

deduceFromClasspath方法是基于 classpath 中类是否存在来进行类型推断的,就是判断指定的类是否存在于 classpath 下, 并根据判断的结果来进行组合推断该应用属于什么类型。deduceFromClasspath 在判断的过程中用到了 ClassUtils 的 isPresent 方法。isPresent方法的核心机制就是通过反射创建指定的类,根据在创建过程中是否抛出异常来判断该类是通过上面的源代码,我们可以看到 deduceFromClasspath 的推断逻辑如下。

  1. 当 DispatcherHandler 存在,并且 DispatcherServlet 和 ServletContainer 都不存在,则返回类型为WebApplicationType.REACTIVE。
  2. 当 SERVLET 或ConfigurableWebApplicationContext 任何一个不存在时,说明当前应用为非 Web 应用,返回 WebApplicationType NONE。
  3. 当应用不为 REACTIVE Web 应用,并且 SERVLET 和ConfigurableWebApplicationContext都存在的情况下,则为 SERVLET 的 Web 应用,返回 WebApplicationType .SERVLET。

加载ApplicationContextlnitializer系列初始化器

ApplicationContextlnitializer是SpringIOC 容器提供的一个接口,它是一个回调接口。

主要目的是允许用户在 ConfigurableApplicationContext 类型(或其子类型)的 ApplicationContext 做 refresh 方法调用刷新之前,对 ConfigurableApplicationContext 实例做进一步的设 置或处理。通常用于应用程序上下文进行编程初始化的 Web 应用程序中。

ApplicationContextlnitializer 接口的 initialize() 方法主要是为了初始化指定的应用上下文。而对应的上下文由参数传入,参数为 ConfigurableApplicationContext 的子类。

在完成了 Web 应用类型推断之后,ApplicationContextlnitializer 便开始进行加载工作,该过程可分两步骤:获得相关实例和设置实例。对应的方法分别为 getSpringFactoriesInstances和 setlnitializers。

(1)进入getSpringFactoriesInstances()方法, 

可以看到,getSpringFactorieslnstances 方 法 依 然 是 通 过 SpringFactoriesL oader 类 的loadFactoryNames() 方法来获得 META-INF/spring.factories 文件中注册的对应配置。

当获取到这些配置类的全限定名之后,便可调用 createSpringFactoriesInstances() 方法进行相应的实例化操作。

完成获取配置类集合和实例化操作之后,调用 setlnitializers 方法将实例化的集合添加到SprinaApplication的成员变量initializers中,类型为List<ApplicationContextlnitiali-zer<?>>。

(2)退出getSpringFactoriesInstances()方法,下一步是setlnitializers()方法,

进入setlnitializers()方法,

setlnitializers()方法将接收到的 initializers 作为参数创建了一个新的 List,并将其赋值给SpringApplication 的 initializers 成员变量。由于是创建了新的 List,并且直接赋值,因此该方法一旦被调用,便会导致数据覆盖,使用时需注意。

加载ApplicationListener系列监听器

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))这行代码是 SpringApplication 的核心构造方法中的逻辑。它用于加载实现了 ApplicationListener 接口的监听器实例集合,并将该监听器实例集合设置到 SpringApplication 的 listeners 变量中。

加载监听器也是从 META-INF/spring.factories 配置文件中加载的,与初始化不同的是,监听器加载的是实现了 ApplicationListener 接口的类。

我们进入getSpringFactoriesInstances()方法,就可以看到SpringFactoriesLoader.loadFactoryNames(type, classLoader)这里是通过 SpringFactoriesLoader 类的 loadFactoryNames 方法来获取 META-INF/spring.factories 中配置 key 为 org.springframework.context.ApplicationListener 的数据。

ApplicationListener 是 Spring 中应用程序事件监听器实现的接口。它基于观察者设计模式的java.util.EventListener 接口的标准。在注册到 Spring ApplicationContext 时,事件将进行相应的过滤,只有匹配的事件对象才会使该监听器被调用。

(1)在 ApplicationListener 接口中,我们可以看到它定义了一个 onApplicationEvent(E event) 方法,当监听事件被触发时,onApplicationEvent 方法就会被调用执行。onApplicationEvent 方法一般用于处理应用程序事件,参数 event 为 ApplicationEvent 的子类,也就是具体要响应处理的各种类型的应用程序事件。

例如,当某个特定事件发生时,你可能想要记录日志、更新数据库、发送电子邮件等等。

(2)另外,ApplicationListener 接口还提供了一个静态方法 forPayload(Consumer<T> consumer),用于创建一个新的 ApplicationListener 实例。

这个方法接受一个 Consumer<T> 类型的参数,这个参数是一个函数接口,它接受一个泛型参数 T,并对其执行一些操作。通过这个方法,你可以将一个 Consumer 函数作为参数,然后返回一个对应的事件监听器。

这个监听器会在事件发生时,调用 Consumer 函数处理事件的有效载荷【即事件中包含的有效信息或数据】。

自定义监听器也跟初始化器一样,依葫芦画瓢就可以了,这里不再举例。

推断应用入口类

deduceMainApplicationClass()这个方法仅仅是找到main方法所在的类,为后面的扫包作准备。deduce是推断的意思。所以准确地说,这个方法作用是推断出主方法所在的类。

deduceMainApplicationClass的实现原理比较巧妙,新建了一个运行时异常对象,通过这个对象获取当前的调用函数堆栈数组StackTrace,之后遍历这个堆栈数组,找到方法名为main的类,返回这个类。

SpringBoot将deduceMainApplicationClass方法推断出来的类赋值给了this.mainApplicationClass。

通过idea的Find Usages查看属性的使用情况,发现只是在banner打印或者log上有涉及,好像没发现有很大的重要性。 

虽然没有发现this.mainApplicationClass比较重要的使用价值,但是推断这个类的实现方法deduceMainApplicationClass的实现原理还是挺巧妙的,值得学习一下。 

4.配置和执行SpringApplication

在SpringApplication.run()方法中,配置并启动应用程序。

这段代码概述了启动过程的各个阶段:

  1. 初始化启动时钟:用于测量启动时间。
  2. 创建并配置环境:设置系统环境变量。
  3. 创建上下文:根据应用类型创建正确的 ApplicationContext 类型。
  4. 准备上下文:执行预启动操作,包括应用引导程序和启动监听器。
  5. 刷新上下文:启动 Spring 应用上下文,加载所有资源和 Bean。
  6. 调用 Runners:调用实现了 CommandLineRunner 或 ApplicationRunner 接口的 Bean。
  7. 启动监听器:通知所有监听器,应用启动完成。
public ConfigurableApplicationContext run(String... args) {
// 为了计时用的,老版本和新版本不一样long startTime = System.nanoTime();// 初始化一个引导器的上下文,这是属于Spring Boot的上下文。后边还有一个Spring的上下文。apach好喜欢context这个东西,证明写框架这个context是真的好用。DefaultBootstrapContext bootstrapContext = createBootstrapContext();// 这是Spring的上下文,在这里定义,在下面进行的初始化ConfigurableApplicationContext context = null;// 配置一个系统属性configureHeadlessProperty();// 获取配置文件的监听器 重点 也是扩展点,凡是读取配置文件的地方都是扩展点,因为配置在配置文件中的initializer、listener都会在某个阶段被调用SpringApplicationRunListeners listeners = getRunListeners(args);// 调用监听器发送启动事件,这里可以通过自定义监听器消费这个事件,处理自己的逻辑listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 解析命令行参数 将其封装成一个ApplicationArguments,这个类的变量name被设置成commandLineArgs字符串,变量source是解析args封装的CommandLineArgs对象。ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 环境预处理ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置忽略beanInfoconfigureIgnoreBeanInfo(environment);// 打印banner信息Banner printedBanner = printBanner(environment);// 创建ApplicationContext容器context = createApplicationContext();context.setApplicationStartup(this.applicationStartup);prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);refreshContext(context);afterRefresh(context, applicationArguments);Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}listeners.started(context, timeTakenToStartup);callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;
}

创建引导上下文createBootstrapContext:createBootstrapContext()方法

SpringApplication会调用createBootstrapContext方法创建引导上下文。

这里就可以看到,在SpringApplication构造方法中的BootstrapRegistryInitializers就会应用到DefaultBootstrapContext中。这也是SpringBoot提供的扩展点之一。

当前扩展点图谱

创建SpringApplicationRunListeners

进入getRunListeners()方法中,

进入其中的SpringApplicationRunListeners类看看,

可以看到,SpringApplicationRunListeners是一个封装类,其中封装了一个SpringApplicationRunListener的列表,当触发某个事件时,就挨个调用其中的SpringApplicationRunListener的对应方法。

 其中,SpringApplicationRunListener负责监听run方法的各个阶段,在不同的阶段监听不同的事件。

SpringBoot默认使用EventPublishingRunListener作为run方法的监听者,我们来看看其源代码。

从代码中可以看到,EventPublishingRunListener会从SpringApplication中获取其Listener,即前面我们在构造方法中看到的ApplicationListener实例。在触发事件时,就是利用Spring的事件机制发布事件,触发ApplicationListener进行触发。

这里需要注意的是,ApplicationListener的来源是spring.factories,而不是我们平时使用的@EventListener。也就是说,如果不写入到spring.factories,那么ApplicationListener就不会出现在这里的EventPublishingRunListener中。

当前扩展点图谱

准备好prepareEnvironment:prepareEnvironment方法

可以看到,把启动参数 args 包装成了 ApplicationArguments 类型的对象,接下来把运行时监听器、启动参数,送到了 prepareEnvironment 方法中创建环境对象。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// 1. 创建一个Environment实例ConfigurableEnvironment environment = getOrCreateEnvironment();// 2. 对Environment进行配置configureEnvironment(environment, applicationArguments.getSourceArgs());// 对environment增加configurationProperty的属性源ConfigurationPropertySources.attach(environment);// 3. 触发监听SpringApplicationRunListener的environmentPrepared事件listeners.environmentPrepared(bootstrapContext, environment);// 将名为defaultProperties的属性源移动到最后DefaultPropertiesPropertySource.moveToEnd(environment);Assert.state(!environment.containsProperty("spring.main.environment-prefix"),"Environment prefix cannot be set via properties.");// 将environment的属性设置到SpringApplication中bindToSpringApplication(environment);// 根据情况对Environment进行一次转换if (!this.isCustomEnvironment) {EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;
}
创建Environment实例,getOrCreateEnvironment() 方法

在SpringApplication.prepareEnvironment方法中,首先会调用getOrCreateEnvironment() 方法创建ConfigurableEnvironment对象。

进入getOrCreateEnvironment() 方法内,可以看到,

创建出来的ConfigurableEnvironment的实际类型会根据SpringApplication初始化时推断出来的WEB应用程序类型而定,如果WEB应用程序类型为SERVLET,则创建出来的ConfigurableEnvironment实际类型为StandardServletEnvironment,并且在初始化StandardServletEnvironment时还会一并将JAVA系统属性和操作系统环境变量这两个外部化配置加载到StandardServletEnvironment中。

printBanner()方法

从 Spring Boot 的 run 方法可以看出,printBanner 方法在 prepareEnvironment 之后,这是因为 application.properties 中有一些关于 Banner 的配置项。需要先解析 application.properties 的值,并将其绑定到对应的 bean 之后,才好进行后续的操作。 

具体的流程如下:

  1. 判断 bannerMode,如果是OFF则表示不打印,如果是LOG则表示打印到文件,否则打印到控制台。
  2. 依据指定位置是是否存在文件,判断 Banner 类型是文本还是图片,文本类型则使用 ResourceBanner,图片类型则使用 ImageBanner, 如果都不是则使用 Spring Boot 默认的 SpringBootBanner。
  3. 调用 Banner 对象的的 printBanner()方法。不同类型的 Banner 的 printBanner()方法不同。

如下是获取 Banner 对象方法,

可以看出,Spring Boot 首先获得 ImageBanner,然后是 ResourceBanner。需要注意的是,这两者可以同时存在则会一次性打印两种 Banner。如果都不满足,还会去获得 fallbackBanner,这个是用户自己设定的兜底 Banner,但是我们很少使用,因为 Spring Boot 内置了兜底方案,也就是 SpringBootBanner。

创建应用程序上下文createApplicationContext:createApplicationContext()方法

此方法主要是用于创建一个应用程序上下文(ApplicationContext),它是一个用于管理Bean的容器。通过该容器,可以实现Bean的实例化、初始化、依赖注入以及销毁等操作。

在Spring框架中,ApplicationContext是核心接口之一,它提供了许多有用的功能,例如:

  • 管理Bean的生命周期:自动实例化、初始化、销毁Bean;

  • 解析Bean之间的依赖关系:自动装配Bean的依赖;

  • 提供国际化支持:根据不同的语言环境加载相应的资源文件;

  • 支持AOP:可以实现面向切面编程;

  • 支持事件传播:可以实现事件的发布和订阅等。

因此,该函数在Spring框架中具有重要的作用,往往是在应用程序的初始化阶段被调用,用于创建和管理Bean的容器。

本次只看它的初始化过程,不对它的功能做过多的分析。

这里的代码体现出了工厂设计模式。 通过SpringApplication类本身实例化的时候,初始化的一个ApplicationContextFactory对象创建了ApplicationContext对象实例。

所以这里的applicationContextFactory.create()方法就是DefaultApplicationContextFactory的create()方法。这里create方法传入的参数当前应用的类型,根据前面分析,当前应用的类型是SERVLET。所以这里的this.webApplicationType的值就是SERVLET。

setApplicationStartup()方法

ApplicationStartup是一个应用启动对象。该函数的作用是将应用启动对象与上下文对象关联起来,以便在上下文对象中可以访问应用启动对象的相关属性和方法。

准备应用程序上下文preparedContext:prepareContext()方法

传入的参数绑定到特定的上下文对象中,为应用程序的启动和运行做好准备。

这个方法主要做了以下操作:

  • 将bootstrapContext绑定到context中,以便在应用程序中访问引导上下文信息。

  • 将environment绑定到context中,以便在应用程序中访问环境变量和属性。

  • 将listeners绑定到context中,以便在应用程序启动和停止时触发相应的监听器事件。

  • 将applicationArguments绑定到context中,以便在应用程序中访问命令行参数。

  • 将printedBanner绑定到context中,以便在应用程序启动时控制是否打印欢迎信息。

通过执行这些操作,prepareContext函数为应用程序的上下文环境准备了必要的信息和配置,使得应用程序能够正常启动和运行。

我们进入到方法看一下。

刷新应用程序上下文refreshContext:refreshContext(context)方法

refreshContext(context)方法用于刷新应用程序的上下文。它会从配置文件中加载所有的Bean并实例化它们,然后将它们注册到应用程序的上下文中。这个方法通常在应用程序启动时调用,以确保所有的Bean都已经被实例化并准备就绪。

下面我们来看一下源码,进入SpringApplication.run方法的refreshContext方法,看到refreshContext的方法内容,继续点击refresh方法,

 Refresh the underlying {@link ApplicationContext}也就是刷新底层的ApplicationContext,继续跟进去,这里要选择AbstractApplicationContext,

refresh方法主要是刷新应用程序上下文,这里主要涉及到准备刷新上下文,调用上下文注册为bean的工厂处理器,初始化上下文的消息源,初始化特定上下文子类中的其他特殊bean,检查监听器bean并注册,最后发布相应的事件并销毁已经创建的单例及重置active标志。

afterRefresh()方法 

接下来调用的是afterRefresh这个方法,

目前,这个方法是个空方法。

listeners.started()方法

调用SpringApplicationRunListeners的started方法,实际上就是调用了所有监听器的started方法,广播SpringBoot已经完成了ApplicationContext初始化的全部过程。

调用callRunners:callRunners()方法

最后,run方法会通过执行callRunners方法来调用ApplicationRunner和CommandLineRunner,目的通过它们来实现在容器启动时执行一些操作。

callRunners()方法大致流程是通过context拿到ApplicationRunner和CommandLineRunner的bean,放入集合然后排序,然后遍历集合将ApplicationArguments 参数传入执行callRunner方法。

我们具体分析一下,

从代码中,我们可以看到,如果有bean的类型是ApplicationRunner或者CommandLineRunner,那么就会执行该bean下的run方法。

以下为ApplicationRunner和CommandLineRunner的源码,我们可以看到两个接口,都只有一个run方法而已。

这两个接口的区别只是run方法的参数不一样,ApplicationRunner 的run方法参数为ApplicationArguments 对象,而CommandLineRunner 的run方法参数为字符串。

  • CommandLineRunner接口,用于指示当一个bean被包含在一个SpringApplication中时应该运行它。可以在同一个应用程序上下文中定义多个CommandLineRunner bean,并且可以使用ordered接口或@Order注释进行排序。
  • ApplicationRunner接口,用于指示当一个bean被包含在一个SpringApplication中时应该运行它。可以在同一个应用程序上下文中定义多个ApplicationRunner bean,并且可以使用ordered接口或@Order注释进行排序。

所以,我们如果想在上下文启动成功之后,做一些操作的话,只需要自定义类实现CommandLineRunner或ApplicationRunner接口就可以了,在实现的run()方法里执行想要自动执行的代码。

另外,当有多个类实现了CommandLineRunner和ApplicationRunner接口时,可以通过在类上添加@Order注解来设定运行顺序。

总结一下就是,该过程可以理解为是SpringBoot完成ApplicationContext初始化前的最后一步工作,我们可以实现自己的ApplicationRunner或者CommandLineRunner,来对SpringBoot的启动过程进行扩展。

当前扩展点图谱

至此run方法就执行完了,程序启动完成。

总结

Spring Boot 的启动流程通过高度自动化的步骤简化了配置和初始化工作。

大致步骤包括:

  1. 启动入口:main 方法及 SpringApplication.run
  2. 初始化 SpringApplication 实例。
  3. 配置和执行启动
  4. 环境准备
  5. 创建和刷新应用上下文
  6. 加载和实例化 Bean
  7. 调用 Runner 接口
  8. 通知启动监听器

稍微细致一点的Springboot 启动过程如下,

  1. 新建module,在主程序类加入断点,启动springboot;
  2. 首先进入SpringAplication类run方法;
  3. run方法新建SpringApplication对象;
  4. SpringApplication对象的run方法,首先创建并启动计时监控类;
  5. 接着通过configureHeadlessProperty设置java.awt.headless的值;
  6. 接着调用getRunListeners创建所有spring监听器;
  7. 接着DefaultApplicationArguments初始化应用应用参数;
  8. 接着prepareEnvironment根据运行监听器和参数准备spring环境;
  9. 接着调用createApplicationContext方法创建应用上下文;
  10. 通过prepareContext准备应用上下文;
  11. refreshContext方法刷新上下文;
  12. 调用stop方法停止计时监控器类;
  13. 调用started发布应用上下文启动完成事件;
  14. callRunners方法执行所有runner运行器;
  15. 调用running发布应用上下文就绪事件;
  16. 最后返回应用上下文。

下面的图片对启动流程做了一个总结:

每个步骤都执行特定的初始化任务,从而实现了 Spring Boot 应用的快速启动和运行。

SpringBoot的启动是一个非常复杂的流程,本文仅仅对SpringBoot的启动做了一些简要的梳理,同时总结了一些比较常见的SpringBoot的扩展点


http://www.mrgr.cn/news/56485.html

相关文章:

  • 新手学STM32的话,先学标准库还是HAL库?
  • 【Flutter】Dart:异步
  • JavaCV 图像灰度化处理
  • 【Unity】Unity Shader学习笔记(八)基础纹理2:高度纹理、法线纹理、模型空间下的法线纹理、切线空间下的法线纹理光照计算
  • 嵌入式 MCU 编程提速秘籍 —— 让你的程序飞起来!
  • RootNeighboursDataset(helpers.dataset_classes文件中的root_neighbours_dataset.py)
  • MySQL实现主从同步
  • jmeter学习(6)逻辑控制器
  • U盘数据丢失不用慌,这4个工具可以帮你恢复。
  • sqlserver小练习
  • 基于Multisim三极管B放大系数放大倍数测量电路设计(含仿真和报告)
  • 手机功耗技术领域
  • Java 实现协同过滤算法推荐算法
  • ecmascript标准
  • Python|基于Kimi大模型,实现上传文档并进行“多轮”对话(7)
  • 【C++刷题】力扣-#350-两个数组的交集II
  • 【校园小情书微信小程序源码】
  • 运用AI实践|如何从AI工具提升工作效率实践
  • 前端算法:字典and哈希表(力扣1题、349题解法)
  • AUTOSAR_EXP_ARAComAPI的6章笔记(2)
  • 在做题中学习(65):Z字形变换
  • spring源码拓展点3之addBeanPostProcesser
  • 2024年9月 GESP CCF C++五级编程能力等级考试认证真题
  • 【四】企业级JavaScript开发开发者控制台
  • Q宠大乐斗鹅号提取器(基于python实现)
  • 动态规划之路径问题