SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

这篇具有很好参考价值的文章主要介绍了SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录和关于我

零丶引入

我在初学spring的时候,很懵逼,因为整个项目中不存在main方法,让我有点摸不着头脑。那时候我知道有个东西叫tomcat是它监听了端口,解析了协议调到了我的servlet。

在我初学SpringBoot的时候,很懵逼,有main方法了,但是tomcat在哪里呢,又是如何启动起来的?。

一丶原生tomcat启动流程

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

在Tomcat总体架构,启动流程与处理请求流程中学习了tomcat总体架构和启动流程。

在springboot内嵌tomcat中则不再使用BootStrap->Catalina这种方式进行启动,而是跨过这一层直接启动了Server。

二丶SpringBoot根据上下文推断ApplicationContext类型

下图是SpringBoot的启动流程,其中红色框框是SpringBoot推断ApplicationContext的步骤

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

这是我们学习springboot内嵌tomcat启动的切入点。

1.推断当前webApplication类型

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

在springboot启动的时候会根据classpath推断当前web应用类型。如果在classpath中存在org.springframework.web.reactive.DispatcherHandler那么会视为REACTIVE类型,如果存在javax.servlet.Servlet,org.springframework.web.context.ConfigurableWebApplicationContext那么会视为SERVLET类型

2.获取webApplication类型对应ApplicationContext

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

SpringBoot会使用ApplicationContextFactory去构建出一个ApplicationContext,一般默认使用DefaultApplicationContextFactory,DefaultApplicationContextFactory会从spring.factories中找出所有的ApplicationContextFactory实现类根据webApplication类型去创建

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

其中有SERVLET类型对应的AnnotationConfigServletWebServerApplicationContext内部类Factory和REACTIVE类型对应的AnnotationConfigReactiveWebServerApplicationContext内部类Factory。

在不使用spring 响应式编程的情况下这里都会使用AnnotationConfigServletWebServerApplicationContext内部类Factory去构建

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

也就是说SpringBoot的启动会使用SpringApplication构建出AnnotationConfigServletWebServerApplicationContext最为Spring上下文。

三丶AnnotationConfigServletWebServerApplicationContext刷新触发tomcat启动

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

在SpringBoot启动的过程中,SpringApplication会触发Spring上下文(ApplicationContext,也就是AnnotationConfigServletWebServerApplicationContext)的刷新

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

AnnotationConfigServletWebServerApplicationContext是AbstractApplicationContext的子类,其refresh刷新方法由AbstractApplicationContext进行了实现。大致流程如下SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

其中onRefresh钩子方法便会触发Tomcat的启动,onRefrsh由 AnnotationConfigServletWebServerApplicationContext父类ServletWebServerApplicationContext进行了实现

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

四丶createWebServer创建web服务器

下图是SpringBoot启动web服务器的全流程

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

1.ServletWebServerFactory

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

WebServerFactory是一个标记接口,ServletWebServerFactory中定义了方法getWebServer(ServletContextInitializer... initializers)来创建WebServer,如参ServletContextInitializer是函数式接口,具备方法onStartup来进行回调。

默认配置下SpringBoot将使用TomcatServletWebServerFactory来创建WebServer。

2.WebServer

WebServer是springboot对服务器的抽象,具备start,stop,getPort,shutDownGracefully(优雅停)方法。

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

3.创建TomcatWebServer流程

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

组装生成TomcatServer主要依赖于Tomcat这个类,Tomcat是嵌入式tomcat启动器,提供众多api来组装tomcat服务器。这一步其实就是在组装tomcat容器模型。

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

组装的过程依赖于Tomcat这个类提供的api

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

可以看到Tomcat中具备Server属性,这代表了web应用服务器

在Server中具备Service数组属性表示web应用服务器中众多的服务

这里只有一个服务——StandardService,其中包含Connector数组和Engine数组

  • Connector

    Connector负责监听客户端请求,返回响应数据。

    SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

    Connector内部由ProtocalHandler属性,其使用AbstractEndpoint监听端口,并将请求交给Processor处理

  • Engine

    Engine负责处理具体的请求。

    SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

    Engine是一个Container内部使用HashMap维护Host(key是hostName,value是Host对象)

    SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

    Host也是一个Container,内部同一使用HashMap维护Context(key是上下文名称,value是Context对象)

    SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

    最终将设置Tomcat对象到TomcatWebServer属性上,并调用Tomcat#start启动Tomcat服务器

五丶TomcatWebServer启动Tomcat

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

TomcatWebServer会调用Tomcat.start方法来启动Tomcat,整个启动流程和原生Tomcat一致

六丶DispatcherServlet是怎么被加到tomcat中的

SpringBoot中如果使用web-stater,那么会引入DispatcherServlet的自动装配,这也就是为什么Tomcat接收到的请求会来到DispatcherServlet,然后由DispatcherServlet反射调用到Controller的方法。

那么DispatcherServlet是什么时候被加入到Tomcat中的呢?

TomcatReactiveWebServerFactory#configureContext方法中会注册TomcatStarterTomcatEmbeddedContext

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

TomcatEmbeddedContextStandardContext的子类,在TomcatEmbeddedContext被调用start的时候,会拿出所有的ServletContainerInitializer调用其onStartup

这里便会拿到TomcatStarterTomcatStarter使用ServletContextInitializer数组记录了ServletWebServerApplicationContext#selfInitialize方法,从而实现ServletWebServerApplicationContext#selfInitialize的回调

SpringBoot之所以这么做是因为ServletContainerInitializer是Servlet规范接口,而ServletContextInitializerSpringBoot定义的接口,利用TomcatStarter将SpringBoot定义的接口嫁接到Servlet定义的规范中从而保证当用户将SpringBoot打包成war包也能触发ServletWebServerApplicationContext#selfInitialize

那么ServletWebServerApplicationContext#selfInitialize做了什么

private void selfInitialize(ServletContext servletContext) throws ServletException {
    // <1> 将当前 Spring 应用上下文设置到 ServletContext 上下文的属性中
    // 同时将 ServletContext 上下文设置到 Spring 应用上下文中
    prepareWebApplicationContext(servletContext);
    // <2> 向 Spring 应用上下文注册一个 ServletContextScope 对象(ServletContext 的封装)(这就是application这种bean作用域生效的本原因)
    registerApplicationScope(servletContext);
    // <3> 向 Spring 应用上下文注册 `contextParameters` 和 `contextAttributes` 属性
    WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
    /**
     * <4> 【重点】先从 Spring 应用上下文找到所有的 ServletContextInitializer
     * 也就会找到各种  RegistrationBean,然后依次调用他们的 `onStartup` 方法,向 ServletContext 上下文注册 Servlet、Filter 和 EventListener
     * 例如 DispatcherServletAutoConfiguration DispatcherServletRegistrationBean 就会注册 @link DispatcherServlet 对象
      * 所以这里执行完了,也就启动了 Tomcat,同时注册了所有的 Servlet,那么 Web 应用准备就绪了
     */
    for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
        beans.onStartup(servletContext);
    }
}

Spring会从BeanFactory拿到所有ServletContextInitializer的实现

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

注册其实都是回调这些ServletContextInitializer的onStartup方法,DispatcherServletRegistrationBean则会将DispatcherServlet注册到ServletContext中。

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

TomcatEmbeddedContext会将DispatcherServlet保证成Wrapper加入到TomcatEmbeddedContext中去。

SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析

七丶总结

这一波学习,让我深刻的理解了Tomcat容器模型,也了解到SpringBoot中使用Filter或者Servlet的时候,为什么要向Spring注入对应的RegsitrationBean,因为只有这样ServletWebServerApplicationContext才能从容器中获取到RegsitrationBean并注册到Tomcat中。文章来源地址https://www.toymoban.com/news/detail-444515.html

到了这里,关于SpringBoot源码学习4——SpringBoot内嵌Tomcat启动流程源码分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot的启动流程源码分析

    new 一个IOC容器,传入配置好的文件xml,在这个地方打bug 在这个debug的栈帧中,下面几个不用看,直接看到getBean 内容如图所示,name传的就是我们在xml的bean标签的id,这里是instanceA 进入到doGetBean后,因为我是从IOC初始化容器debug进来的所以第一次通过。 Object sharedInstance = getSingl

    2024年01月24日
    浏览(34)
  • SpringBoot3.X源码分析(启动流程)

    1 启动入口 静态辅助类,可用于运行使用默认配置(即我们添加的一系列注解)的指定源的 SpringApplication 。 primarySource - 要载入的主要源,即指定源,这里为传入的 Application.class  Class? :泛型决定了任何类都可以传入 args - 应用程序参数(通常从main方法传递) 返回:正在运

    2024年01月23日
    浏览(29)
  • SpringBoot项目配置Eureka时,内嵌TomCat无法启动java.lang.IllegalStateException: StandardEngine[Tomcat].Standa

    java.lang.IllegalStateException: StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[] failed to start SpringBoot项目可以正常启动,但是一添加@EnableEurekaServer相关注解再启动SpringBoot就报如上错误。我是因为有两个jdk版本,一个8一个17. 从根本原因可以看出是SpringBoot的内嵌Tomcat报错,这是

    2024年02月09日
    浏览(33)
  • SpringBoot-Run启动流程(源码分析)—看不懂来揍我

    目录 前言 Run()方法 1、实例化SpringApplication对象 1、加载容器 2、装配初始化器 3、装配监听器  4、加载主类 2、执行Run()方法 1、设置headless 2、启用SpringApplicationListener 3、加载Banner 1、图片Banner 2、文本Banner 4、异常报告类加载 5、准备上下文         6、刷新上下文 7、系统

    2024年02月14日
    浏览(27)
  • SpringBoot 升级内嵌Tomcat

    最近公司的一个老项目需要升级下Tomcat,由于这个项目我完全没有参与,所以一开始我以为是一个老的Tomcat项目,升级它的Tomcat依赖或者是Tomcat容器镜像,后面发现是一个SpringBoot项目,升级的是SpringBoot内置的Tomcat。 这样的升级可以保证项目最小变动的情况下,将一个不安全

    2024年02月13日
    浏览(27)
  • SpringBoot 源码分析(四) 内置Tomcat分析

    Tomcat文件的目录结构 启动一个Tomcat服务是执行的bin目录下的脚本程序, startup.bat 和 startup.sh .一个是windows的脚本,一个是Linux下的脚本,同样还可以看到两个停止的脚本 shutdown.bat 和 shutdown.sh . startup.bat 脚本内容 catalina.bat 脚本文件 doStart 方法 最后会执行的程序是 MAINCLASS 变量

    2024年02月08日
    浏览(29)
  • SpringBoot内嵌Tomcat版本升级步骤

    由于Apache Commons FileUpload对请求部分要处理的数量未做限制,导致攻击者可以利用此漏洞恶意上传或一系列上传触发拒绝服务。 Apache Tomcat由于使用Apache Commons FileUpload的打包重命名副本来提供Jakarta Servlet规范中定义的文件上传功能。因此,Apache Tomcat也受到CVE-2023-24998影响。 影

    2024年02月11日
    浏览(34)
  • springboot启动流程源码解析(带流程图)

    本文自己写的(头条也有这篇文章),若有问题,请指正。 大致流程如下: 1. 初始化SpringApplication,从META-INF下的spring.factories读取 ApplicationListener/ApplicationContextInitializer 2.运行SpringApplication的run方法 3.读取项目中环境变量、jvm配置信息、配置文件信息等 4.创建Spring容器对象(

    2024年02月08日
    浏览(33)
  • 【SpringBoot3.0源码】启动流程源码解析 • 上

    SpringBoot启动类:

    2024年02月02日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包