返回顶部
首页 > 资讯 > 后端开发 > JAVA >Spring Boot的启动流程
  • 430
分享到

Spring Boot的启动流程

springbootspringjava 2023-08-16 15:08:31 430人浏览 安东尼
摘要

文章目录 Spring BootSpring Boot概念Spring Boot的启动流程1. 构造SpringApplection的实例2. 调用实例的run方法 Spring Boot启动流程总结: Spring

Spring Boot

spring Boot概念

Spring Boot是作为Spring的脚手架框架,其本身并不提供Spring的核心功能,而是来达到快速构建项目、预置三方配置、开箱即用的目的

从本质上来说,Spring Boot就是Spring,它做了那些没有它你自己也会去做的Spring Bean配置。

Spring Boot使用“习惯优于配置”的理念让你的项目快速地运行起来,使用Spring Boot很容易创建一个能独立运行、准生产级别、基于Spring框架的项目,使用Spring Boot你可以不用或者只需要很少的Spring配置。

Spring Boot有如下的优点:

  • 可以快速构建项目;
  • 可以对主流开发框架的无配置集成;
  • 项目可独立运行,无需外部依赖Servlet容器
  • 提供运行时的应用监控
  • 可以极大地提高开发、部署效率;
  • 可以与云计算天然集成。

Spring Boot的启动流程

首先,Spring Boot项目创建完成会默认生成一个名为 *Application 的入口类,我们是通过该类的main方法启动Spring Boot项目的。在main方法中,通过SpringApplication的静态方法,即run方法进行SpringApplication类的实例化操作,然后再针对实例化对象调用另外一个run方法来完成整个项目的初始化和启动。

在这里插入图片描述
再调用另外一个run方法:
在这里插入图片描述
我们可以看到run方法里主要干了两件事:

  1. 构造SpringApplection的实例
  2. 调用实例的run方法

1. 构造SpringApplection的实例

构造SpringApplection的实例过程主要干了下面几件事:

  1. 把参数sources设置到SpringApplection属性中,这个sources可以是任何类型的参数
  2. 获取应用类型,判断是否是WEB程序,并设置到webEnvironment的boolean属性中
  3. 创建并初始化ApplectionInitializer(初始化器),设置到initializers属性中
  4. 创建并初始化ApplicationListener(初监听器),设置到listeners属性中
  5. 初始化主类mainApplectionClass,定位main方法。

我们追踪其源码
在这里插入图片描述
然后我们跟进这个 this构造,可以看到初始化了很多成员变量:

在这里插入图片描述
我们将其提炼出来,他主要进行了下面的代码

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//获取应用类型,判断是不是web程序this.webApplicationType = WebApplicationType.deduceFromClasspath();//获取所有初始化器this.setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//获取所有监听器this.setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//定位main方法this.mainApplicationClass = deduceMainApplicationClass();}

首先是把参数sources设置到SpringApplection属性中,这个sources可以是任何类型的参数

然后我们再获取应用类型, 判断是否是web程序,并设置到webEnvironment的boolean属性中,我们跟进deduceFromClasspath函数
在这里插入图片描述

从返回结果我们可以看出应用类型一共有三种,分别是

返回值说明
NONE非web应用,即不会启动服务器
SERVLET基于servlet的web应用
ReactIVE响应式web应用(暂未接触过)
static WebApplicationType deduceFromClasspath() {    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) &&     !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) &&     !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {        return REACTIVE;    } else {        String[] var0 = SERVLET_INDICATOR_CLASSES;        int var1 = var0.length;        for(int var2 = 0; var2 < var1; ++var2) {            String className = var0[var2];            if (!ClassUtils.isPresent(className, (ClassLoader)null)) {                return NONE;            }        }        return SERVLET;    }}

判断一共涉及四个常量:
WEBFLUX_INDICATOR_CLASS , WEBmvc_INDICATOR_CLASS,JERSEY_INDICATOR_CLASS,SERVLET_INDICATOR_CLASSES

SpringBoot在初始化容器的时候,会对以上四个常量所对应的class进行判断,看看他们是否存在,从而返回应用类型!

常量代表哪些class,也在当前类中:

在这里插入图片描述

然后是创建并初始化ApplectionInitializer,设置到initializers属性中,该步骤调用了getSpringFactoriesInstances函数,我们跟进其源码:

private  Collection getSpringFactoriesInstances(Class type) {return getSpringFactoriesInstances(type, new Class[] {});}private  Collection getSpringFactoriesInstances(Class type, Class[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates// 获取所有初始化器的名称集合Set names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 根据名称集合实例化这些初始化器List instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);// 排序AnnotationAwareOrderComparator.sort(instances);return instances;}

从源代码中,我们可以看出是在META-INF/spring.factories配置文件里获取初始化器,然后实例化、排序后再设置到initializers属性中。

然后是创建并初始化ApplicationListener,设置到listeners属性中,该步骤调用了getSpringFactoriesInstances函数,步骤和上一步获取初始化器一样

最后初始化主类mainApplectionClass,我们继续跟踪源码进入deduceMainApplicationClass方法

private Class deduceMainApplicationClass() {try {    // 通过创建运行时异常的方式获取栈StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();// 遍历获取main方法所在的类并且返回for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;}

其实遍历当前虚拟机栈获取main方法所在的类并且返回

2. 调用实例的run方法

SpringApplication调用的run方法的大致流程,如下图:

在这里插入图片描述
其中,SpringApplication在run方法中重点做了以下操作:

  • 获取监听器和参数配置;
  • 打印Banner信息;
  • 创建并初始化容器;
  • 监听器发送通知。

当然,除了上述核心操作,run方法运行过程中还涉及启动时长统计、异常报告、启动日志、异常处理等辅助操作。

比较完整的流程,可以参考如下源代码:

public ConfigurableApplicationContext run(String... args) {    // 创建StopWatch对象,用于统计run方法启动时长。    StopWatch stopWatch = new StopWatch();    // 启动统计    stopWatch.start();    ConfigurableApplicationContext context = null;    Collection exceptionReporters = new ArrayList<>();    // 配置Headless属性    configureHeadlessProperty();    // 获得SpringApplicationRunListener数组,    // 该数组封装于SpringApplicationRunListeners对象的listeners中。    SpringApplicationRunListeners listeners = getRunListeners(args);    // 启动监听,遍历SpringApplicationRunListener数组每个元素,并执行。    listeners.starting();    try {        // 创建ApplicationArguments对象        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);        // 加载属性配置,包括所有的配置属性。        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);        configureIgnoreBeanInfo(environment);        // 打印        Banner Banner printedBanner = printBanner(environment);        // 创建容器        context = createApplicationContext();        // 异常报告器        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);        // 准备容器,组件对象之间进行关联。        prepareContext(context, environment, listeners, applicationArguments, printedBanner);        // 初始化容器        refreshContext(context);        // 初始化操作之后执行,默认实现为空。        afterRefresh(context, applicationArguments);        // 停止时长统计        stopWatch.stop();        // 打印启动日志        if (this.logStartupInfo) {            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);        }        // 通知监听器:容器完成启动。        listeners.started(context);        // 调用ApplicationRunner和CommandLineRunner的运行方法。        callRunners(context, applicationArguments);    } catch (Throwable ex) {        // 异常处理        handleRunFailure(context, ex, exceptionReporters, listeners);        throw new IllegalStateException(ex);    }        try {        // 通知监听器:容器正在运行。        listeners.running(context);    } catch (Throwable ex) {        // 异常处理        handleRunFailure(context, ex, exceptionReporters, null);        throw new IllegalStateException(ex);    }    return context;}

Spring Boot启动流程总结

--------------------------------创建springbootApplication对象---------------------------------------------1. 创建springbootApplication对象springboot容器初始化操作2. 获取当前应用的启动类型。2.1:通过判断当前classpath是否加载servlet类,返回servlet web启动方式。2.2:webApplicationType三种类型:1.reactive:响应式启动(spring5新特性)2.none:即不嵌入web容器启动(springboot放在外部服务器运行 )3.servlet:基于web容器进行启动3. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationContextInitializer装配到集合4. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationListener装配到集合5. mainApplicationClass,获取当前运行的主函数------------------调用springbootApplication对象的run方法,实现启动,返回当前容器的上下文----------------------------------------------1. 调用run方法启动2. StopWatch stopWatch = new StopWatch(),记录项目启动时间3. getRunListeners,读取META-INF/spring.factores,将SpringApplicationRunListeners类型存到集合中4. listeners.starting();循环调用starting方法5. prepareEnvironment(listeners, applicationArguments);将配置文件读取到容器中读取多数据源:classpath:/,classpath:/config/,file:./,file:./config/底下。其中classpath是读取编译后的,file是读取编译前的支持yml,yaml,xml,properties6. Banner printedBanner = printBanner(environment);开始打印banner图,就是sprongboot启动最开头的图案7. 初始化AnnotationConfigServletWebServerApplicationContext对象8. 刷新上下文,调用注解,refreshContext(context);9. 创建Tomcat10. 加载springMVC11. 刷新后的方法,空方法,给用户自定义重写afterRefresh()12. stopWatch.stop();结束计时13. 使用广播和回调机制告诉监听者springboot容器已经启动化成功,listeners.started(context);14. 使用广播和回调机制告诉监听者springboot容器已经启动化成功, listeners.running(context);15. 返回上下文

来源地址:https://blog.csdn.net/weixin_45525272/article/details/126502991

--结束END--

本文标题: Spring Boot的启动流程

本文链接: https://www.lsjlt.com/news/371589.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Spring Boot的启动流程
    文章目录 Spring BootSpring Boot概念Spring Boot的启动流程1. 构造SpringApplection的实例2. 调用实例的run方法 Spring Boot启动流程总结: Spring ...
    99+
    2023-08-16
    spring boot spring java
  • Spring boot 启动流程及外部化配置方法
    目录Main 入口SpringApplication判断运行环境初始化器和监听器总结执行 run 方法环境变量及配置prepareEnvironmentgetOrCreateEnvi...
    99+
    2022-12-08
    Spring boot 启动流程 springboot外部化配置
  • Spring Boot面试必问之启动流程知识点详解
    目录一 面试提问1.1 Spring Boot启动流程1.2 SpringBoot自动装配二 知识点详解2.1 SpringBoot核心注解:2.2详细启动流程(结合源码)总结一 面...
    99+
    2024-04-02
  • Spring Boot启动过程完全解析(一)
    之前在排查一个线上问题时,不得不仔细跑了很多遍Spring Boot的代码,于是整理一下,我用的是1.4.3.RELEASE。  首先,普通的入口,这没什么好说的,我就随便贴贴代码了:SpringApplication.run(Applic...
    99+
    2023-05-31
    spring boot启动 spring boo
  • Spring Boot启动的原理是什么
    本文小编为大家详细介绍“Spring Boot启动的原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Boot启动的原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起...
    99+
    2024-04-02
  • Spring Boot web项目的TDD流程
    目录概述1 技术工具2 构建Spring Boot工程3 开始编写测试和代码1 Controller2 Service3 Repository4 总结概述 测试驱动开发可以分为三个周...
    99+
    2024-04-02
  • spring boot 如何指定profile启动
    spring boot项目可为不同的环境配置相应的配置文件 如下图所示: pom.xml配置如下: <dependencies> 其他依赖 <...
    99+
    2024-04-02
  • Spring容器启动流程是什么
    本篇内容介绍了“Spring容器启动流程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!源码解析考虑到直接看源码是一个非常枯燥无味的过程...
    99+
    2023-06-15
  • Spring Boot修改启动端口的方法
    spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境。可是当我们要同时启动2个springboot工程时,就会有问题,有可能会因为8080端口被第一个应用占用而导致第二个应用无法启动,这...
    99+
    2023-05-31
    spring boot 启动端口
  • Spring体系的各种启动流程详解
    目录基本组件基础流程Springframework1、容器类2、注解定义bean读取器3、BeanFactoryPostProcessor4、refreshSpringMVC1、配置...
    99+
    2024-04-02
  • Spring Boot 启动、停止、重启、状态脚本
    此脚本用来管理 SpringBoot 项目的进程状态。 有提示功能。 把脚本丢到项目文件夹, 添加执行权限即可。 如果 jenkins 使用这个脚本, 需要在 java -jar 命...
    99+
    2024-04-02
  • Linux启动与停止spring boot工程的脚本示例
    在springboot项目启动有三种方式: 1、运行主方法程序 2、使用命令mvn spriqiqmHQsng-boot:run 在命令行运行 3、使用 mvn packpage打包位jar文件以后,使用java ...
    99+
    2022-06-04
    停止springboot应用 springboot 启动 停止springboot项目
  • Spring Boot如何通过java -jar启动
    目录Pre引导新建工程 打包 启动java -jar 干啥的打包插件spring-boot-maven-plugin简介包结构Archive的概念JarFileJarLauncher...
    99+
    2024-04-02
  • 如何通过java -jar启动Spring Boot
    这篇文章给大家介绍如何通过java -jar启动Spring Boot,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。新建工程 打包 启动新创建一个Spring Boot的工程其中打包的配置为<build>&...
    99+
    2023-06-15
  • Spring Boot启动端口修改方法
    spring boot是个好东西,可以不用容器直接在main方法中启动,而且无需配置文件,方便快速搭建环境。可是当我们要同时启动2个springboot工程时,就会有问题,有可能会因为8080端口被第一个应用占用而导致第二个应用无法启动,这...
    99+
    2023-05-31
    spring boot 启动端口
  • Spring源码分析容器启动流程
    目录前言源码解析1、初始化流程流程分析核心代码剖析2、刷新流程流程分析核心代码剖析前言 本文基于 Spring 的 5.1.6.RELEASE 版本 Spring的启动流程可以归纳为...
    99+
    2024-04-02
  • Spring Boot 启动加载数据 CommandLineRunner的使用
    实际应用中,我们会有在项目服务启动的时候就去加载一些数据或做一些事情这样的需求。 为了解决这样的问题,spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRunner 来实现。很简单,只需要一个类就可以,无需其...
    99+
    2023-05-31
    spring boot 加载
  • Spring boot CommandLineRunner启动任务传参的方法
    这篇文章主要讲解了“Spring boot CommandLineRunner启动任务传参的方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring bo...
    99+
    2023-06-30
  • SpringBoot 的启动流程
    SpringBoot 的启动流程 一、 生成SpringApplication对象 1. webApplicationType = 推测web应用的类型(NODE(普通项目)、SERVLET(Serv...
    99+
    2023-09-28
    spring boot spring java
  • spring boot 不连接数据库启动的解决
    目录spring boot 不连接数据库启动原因在于解决方法SpringBoot项目取消数据库配置1. 错误2. 原因3. 如何不配spring boot 不连接数据库启动 用spr...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作