Tomcat在Spring Boot中是怎么启动的?

Spring Boot是如何启动Tomcat的 在创建Spring容器过程中,会利⽤@ConditionalOnClass技术来判断当前classpath中是否存在Tomcat依赖,如果存在则会⽣成⼀个启动Tomcat的Bean。Spring容器创建完之后,就会获取启动Tomcat的Bean,并创建Tomcat对象,并绑定端⼝等,然后启动Tomcat。实现一键启动,无需手动部署 WAR 文件。动态选择服务器(Tomcat/Jetty/Undertow)。:默认 NIO 连接器,支持线程池参数调优。:Tomcat 作为库打包到应用中,启动 Tomcat。 阅读详情

Spring Boot一个非常突出的优点就是不需要我们额外再部署Servlet容器,它内置了多种容器的支持。我们可以通过配置来指定我们需要的容器。

本文以我们平时最常使用的容器Tomcat为列来介绍以下两个知识点:

  • Spring Boot是怎么整合启动Tomcat容器的;
  • 在Spring Boot中,怎么进行Tomcat的深度配置。

Spring Boot整合启动Tomcat的流程

对于看源代码,每个人都有自己的方法。我自己在看源代码的时候喜欢结合IDEA的Debug功能一起看。比如说现在我们要研究Spring Boot是在哪个环节点启动Tomcat的,
我的思路是:Tomcat在启动时会调用各个组件的init方法和start方法,那么我只需要在这些方法上打上端点,然后就能在调用栈上看出Spring Boot是在哪个环节点启用
Tomcat的了。

按照这个思路,我在Tomcat的Connector组件的init方法上打了端点,通过调用栈能很清楚的看出Spring Boot是在容器的onRefresh方法中调用Tomcat的。

protected void onRefresh() {
    super.onRefresh();
    try {
        this.createWebServer();
    } catch (Throwable var2) {
        throw new ApplicationContextException("Unable to start web server", var2);
    }
}

在这里插入图片描述

找到了调用点,那么一切都好办了。从上面的方法中可以看出,重点内容就在this.createWebServer()这个方法中。

在Spring Boot中使用的容器类是ServletWebServerApplicationContext系列的容器,这个系列的容器可以内嵌Web容器。这个我们
可以从这个容器的属性和方法中可以看出来。

public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext {
    //...省略部分代码
    public static final String DISPATCHER_SERVLET_NAME = "dispatcherServlet";
    //内嵌容器
    private volatile WebServer webServer;
    private ServletConfig servletConfig;
   
    //...省略部分代码
    //创建Web容器
    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        //webServer和servletContext都是null,表示还没创建容器,进入创建容器的逻辑
        if (webServer == null && servletContext == null) {
            //获取创建容器的工厂,可以通过WebServerFactoryCustomizer接口对这个工厂进行自定义设置
            ServletWebServerFactory factory = this.getWebServerFactory();
            //具体的创建容器的方法,我们进去具体看下
            this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
        } else if (servletContext != null) {
            try {
                this.getSelfInitializer().onStartup(servletContext);
            } catch (ServletException var4) {
                throw new ApplicationContextException("Cannot initialize servlet context", var4);
            }
        }
        this.initPropertySources();
    }
}

下面是TomcatServletWebServerFactory的getWebServer方法。

public class TomcatServletWebServerFactory的getWebServer{
//...

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
    //创建Tomcat容器
    Tomcat tomcat = new Tomcat();
    File baseDir = (this.baseDirectory != null ? this.baseDirectory
            : createTempDir("tomcat"));
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    //创建连接器,默认NIO模式,可以通过WebServerFactoryCustomizer改变具体模式
    Connector connector = new Connector(this.protocol);
    tomcat.getService().addConnector(connector);
    //自定义连接器
    customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    configureEngine(tomcat.getEngine());
    //可以通过WebServerFactoryCustomizer添加额外的连接器,这边将这些连接器绑定到Tomcat
    for (Connector additionalConnector : this.additionalTomcatConnectors) {
        tomcat.getService().addConnector(additionalConnector);
    }
    //组测Listener、Filter和Servlet,自定义Context等操作
    //这个方法可以重点看下
    prepareContext(tomcat.getHost(), initializers);
    //创建TomcatWebServer,并调用start方法
    return getTomcatWebServer(tomcat);
}

//内嵌的Tomcat容器
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
        //这边触发Tomcat的启动流程,是Tomcat启动的入口点
    initialize();
}
//...省略部分代码
}

在这里插入图片描述

至此Spring Boot内嵌的Tomcat已将顺序启动了。那么Spring Boot是在什么时候注册DispatchServlet的呢?

配置Listener、Filter和Servlet
Spring Boot配置Listener、Filter和Servlet可以參考我之前写的文章Spring Boot使用嵌入式容器,那怎么配置自定义Filter呢

推荐使用ServletListenerRegistrationBean、FilterRegistrationBean和ServletRegistrationBean的方式注册Listener、Filter和Servlet。

Spring Boot注册DispatcherServlet
在传统的Spring MVC项目中,我们都会在web.xml中注册DispatcherServlet这个入口类,那么在Spring Boot中是在哪里注册的呢?

大家如果看Spring Boot的源代码,这边有个小技巧大家可以参考下。就是Spring Boot把之前传统项目中的配置项都通过AutoConfig的形式
做配置了。所以这边在寻找DispatcherServlet是在哪里配置的也可以顺着这个思路去寻找。

在IDEA的类查找功能中输入DispatcherServlet关键字,我们能看到一个DispatcherServletAutoConfiguration类。从名字上就能看出这个
类是DispatcherServlet的自动配置类,我们点进去看下是否是在这个类内部注册的DispatcherServlet?

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
@EnableConfigurationProperties(ServerProperties.class)
public class DispatcherServletAutoConfiguration {

  /*
   * The bean name for a DispatcherServlet that will be mapped to the root URL "/"
   */
  public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

  /*
   * The bean name for a ServletRegistrationBean for the DispatcherServlet "/"
   */
  public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

  @Configuration
  @Conditional(DefaultDispatcherServletCondition.class)
  @ConditionalOnClass(ServletRegistration.class)
  @EnableConfigurationProperties(WebMvcProperties.class)
  protected static class DispatcherServletConfiguration {

    private final WebMvcProperties webMvcProperties;

    public DispatcherServletConfiguration(WebMvcProperties webMvcProperties) {
      this.webMvcProperties = webMvcProperties;
    }

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServlet dispatcherServlet() {
      DispatcherServlet dispatcherServlet = new DispatcherServlet();
      dispatcherServlet.setDispatchOptionsRequest(
          this.webMvcProperties.isDispatchOptionsRequest());
      dispatcherServlet.setDispatchTraceRequest(
          this.webMvcProperties.isDispatchTraceRequest());
      dispatcherServlet.setThrowExceptionIfNoHandlerFound(
          this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
      return dispatcherServlet;
    }

    @Bean
    @ConditionalOnBean(MultipartResolver.class)
    @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
    public MultipartResolver multipartResolver(MultipartResolver resolver) {
      // Detect if the user has created a MultipartResolver but named it incorrectly
      return resolver;
    }

  }

  @Configuration
  @Conditional(DispatcherServletRegistrationCondition.class)
  @ConditionalOnClass(ServletRegistration.class)
  @EnableConfigurationProperties(WebMvcProperties.class)
  @Import(DispatcherServletConfiguration.class)
  protected static class DispatcherServletRegistrationConfiguration {

    private final ServerProperties serverProperties;

    private final WebMvcProperties webMvcProperties;

    private final MultipartConfigElement multipartConfig;

    public DispatcherServletRegistrationConfiguration(
        ServerProperties serverProperties, WebMvcProperties webMvcProperties,
        ObjectProvider<MultipartConfigElement> multipartConfigProvider) {
      this.serverProperties = serverProperties;
      this.webMvcProperties = webMvcProperties;
      this.multipartConfig = multipartConfigProvider.getIfAvailable();
    }

        //很熟悉的代码有没有,ServletRegistrationBean就是我们上一节中介绍的注册Servlet的方式
        //只不过这边注册的是DispatcherServlet这个特殊的Servlet
    @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public ServletRegistrationBean<DispatcherServlet> dispatcherServletRegistration(
        DispatcherServlet dispatcherServlet) {
      ServletRegistrationBean<DispatcherServlet> registration = new ServletRegistrationBean<>(
          dispatcherServlet,
          this.serverProperties.getServlet().getServletMapping());
      registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
      registration.setLoadOnStartup(
          this.webMvcProperties.getServlet().getLoadOnStartup());
      if (this.multipartConfig != null) {
        registration.setMultipartConfig(this.multipartConfig);
      }
      return registration;
    }

  }

//...省略部分代码
}

好了通过这边的介绍,我们直到DispatcherServlet是通过DispatcherServletAutoConfiguration这个自动配置类注册的。

Spring Boot中关于Tomcat的一些其他配置

在这里插入图片描述

这边给出一个配置的列子

server:
  port: ${port:9999}
  tomcat:
    accept-count: 200
    #最好进行这段配置,默认会在tmp目录下创建,Linux有时会有定时任务删除tmp目录下的内容
    basedir: my-tomcat
    accesslog:
      enabled: true
      pattern: '%t %a "%r" %s %S (%b M) (%D ms)'
      max-http-post-size: 2MB
      max-swallow-size: 2M
    uri-encoding: GBK
    threads:
      max: 100
      min-spare: 10

具体使用时可以参考Spring Boo官网关于Tomcat的配置。

一些其他类
Spring Boot还提供了很多自定义类,让用户对Tomcat的组件做自定义配置。这个符合Spring的设计哲学:只提供选择,而不是强制用户使用某项技术。

关于Tomcat的自定义配置类还有以下几个,大家可以按需使用。

  • WebServerFactoryCustomizer接口:自定义Web容易工厂
  • WebServerFactoryCustomizerBeanPostProcessor处理类:WebServerFactoryCustomizer类通过 WebServerFactoryCustomizerBeanPostProcessor类生效
  • TomcatConnectorCustomizer:连接器自定义处理类
  • TomcatContextCustomizer:Context自定义接口
Spring Boot启动过程(六):内嵌Tomcat中StandardHost、StandardContext和StandardWrapper的启动 看代码有助于线上出现预料之外的事的时候,不至于心慌。。。    StandardEngine[Tomcat].StandardHost[localhost]的启动与StandardEngine不在同一个线程中,它的start: // Start our child containers, if any Container children[] = f 阅读详情

相关推荐

【SpringBoot系列】Spring Boot 中tomcat的启动

好久没写了,今天继续,虽然类似的文章在网上也能搜到,但是还是自己记录下,也是实际的去探索下,说一下自己的方法上面堆栈的第4个,也就是run:307 堆栈,看到如下代码这里可以看到根据不同的webApplicationType 会创建不同的web服务器这里的问题是webApplicationType 是怎么赋值的呐?直接搜索,可以看到构造函数的时候进行赋值的点进去看实现,是一个静态的函数,是根据当前路径下的类判断,返回是REACTIVE 还是Servlet。

我是香菜 1051

SpringBoot内置Tomcat启动原理源码分析

1、获取SpringBoot内置Tomcat自动配置类:   在SpringBoot项目中引入spring-boot-starter-web依赖,就默认使用Tomcat容器,该依赖中引入spring-boot-starter-tomcat、spring-webmvc,就引入了tomtcat核心依赖和springMvc相关jar包,这样就间接地引入了tomcat。   在执行SpringBoot项目启动类的main()方法,启动SpringBoot项目的过程中会加...

qq_20579853的博客 1991

保姆级教程:手把手教你用Jacquard V2数据集训练机器人抓取模型(附完整代码)

本文提供了一份详细的保姆级教程,手把手教你使用Jacquard V2数据集训练机器人抓取模型。从环境配置、数据准备到模型架构设计、训练优化和实际部署,全程解析并附完整代码,帮助开发者快速掌握视觉抓取技术。

weixin_29031057的博客 315

java web初始化实例,SpringBoot源码分析-初始化Tomcat-ServletWebServerFactory实例化

概要详细剖析ServletWebServerFactory实例化过程,整个过程使用多次后置处理对Bean实例化进行干预,完成TomcatServletWebServerFactory进行初始化ServletWebServerFactory实例化Spring容器在刷新容器的时候创建WebServer之前,先要创建ServletWebServerFactoryServletWebServerFacto...

weixin_33303537的博客 3355

零基础微信理财通基金实操指南(2026版)

先活下来:保证不亏大钱,再想赚钱慢慢变富:年化10%,7年翻倍,这已经很好了开始比完美重要:今天先存100元到零钱通,就是最好的开始现在打开微信,进入理财通,完成第一步风险测评吧!有任何问题可以随时问,我会用最通俗的方式解释。

老韩的Linux云计算架构师进阶之路 1693

【已解决】App unavailable Unfortunately, Claude is only available in certain countries and regions

App unavailable Unfortunately, Claude is only available in certain countries and regions right now. We will soon publish a list of supported locations on our website.

weixin_43941438的博客 3万+

新版Springboot内嵌Tomcat版ServletWebServerFactoryAutoConfiguration相关源码分析及SpringBoot启动Tomcat容器初始化过程

源码分析 注: 1.Embedded Container新版都没有了,直接看ServletWebServerFactoryAutoConfiguration 2.Container后续统统都叫WebServer了即原来servlet容器就是Tomcat或者其他的WebServer ServletWebServerFactoryAutoConfiguration @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessor

wrz115533的博客 1万+

UE4免费资产库新玩法:Quixel Bridge插件安装与Megascans资源导入全攻略

本文详细介绍了如何在UE4中安装Quixel Bridge插件并导入Megascans资源,帮助开发者快速获取高质量3D资产。通过分步教程和实用技巧,提升游戏或影视场景的制作效率,特别适合需要真实感环境的项目。

weixin_27729671的博客 370

springboot 使用tomcat详解

这里要明白,不然你后面不知道是怎么调用到这里来的TomcatStarter 注意 该类实现 ServletContainerInitializer ,这个是servlet-api的接口,tomcat启动会调用该实现类的。

sunshinezx8023的博客 3602

树莓派5首次开机保姆级教程(无显示器通过VNC连接树莓派桌面)

选择 Interface Options > VNC > Yes 启用服务。2.在Windows电脑上安装VNC软件。重启树莓派:sudo reboot。3.使用VNC远程访问树莓派桌面。

qq_34184505的博客 2351

【数字IC设计】Centos 7桌面版 安装Synopsys EDA Tools

简称DC,是Synopsys公司用于做电路综合的核心工具,可以将HDL描述的电路转换为基于工艺库的门级网表。

qiumingT的博客 9807

springboot 2.X后内置tomcat自定义配置

目录 使用Tomcat启用多个连接器 配置springboot中Web服务器-自带默认tomcat配置 由官网可知,springboot在2.0以后,对于tomcat提供自定义接口发生了变化;如官网提供配置多个tomcat链接器: 使用Tomcat启用多个连接器 可以添加org.apache.catalina.connector.Connector到 To...

平凡之路无尽路的博客 1万+

SpyGlass Lint脚本实战:如何用TCL自动化RTL代码检查(附完整配置模板)

本文详细介绍了如何利用TCL脚本实现SpyGlass Lint工具的自动化RTL代码检查。通过构建模块化、工程化的脚本框架,文章提供了从环境搭建、核心配置、规则定制到豁免管理的完整实战指南,并附有可复用的配置模板,旨在帮助IC设计工程师构建高效、一致的代码质量检查流水线。

weixin_29204205的博客 136

spring boot启动加载tomcat原理深度剖析

spring boot应用打包成Fat jar时,启动内嵌tomcat的原理;spring boot应用打包成WAR时,外部tomcat启动spring boot SpringApplication的原理;自动化配置Servlet/ServletFilter/ServletListener的原理

ac_dao_di的专栏 5793

基于ESP32和OV5640的目标检测系统

本文详细介绍了基于ESP32-S3和OV5640摄像头构建目标检测系统的完整方案。系统采用YOLOv8-Nano轻量级模型,通过INT8量化实现边缘部署,在UXGA分辨率下达到25fps帧率。文章从硬件选型、图像采集优化、模型量化部署、实时推理流水线构建等维度展开,重点解决了内存管理、电源稳定性和异常处理等嵌入式系统关键问题。该方案在资源受限条件下实现了150ms以内的端到端延迟,为物联网视觉应用提供了低成本、低功耗的解决方案,适用于智能家居、工业检测等多个场景。

reset2021的博客 329

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Spring Boot 中 Tomcat 的启动流程

特性说明默认容器Spring Boot 默认使用嵌入式 Tomcat(启动入口→refresh()→→核心组件ConnectorServlet 初始化→→init()HTTP 监听→→ NIO 线程池启动性能优化使用 NIO、延迟加载、GZIP 压缩、APR/native 模式源码路径。

红血哥 1404

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

springboot启动后怎么访问_Tomcat在Spring Boot中是怎么启动的呢?

Spring Boot一个非常突出的优点就是不需要我们额外再部署Servlet容器,它内置了多种容器的支持。我们可以通过配置来指定我们需要的容器。本文以我们平时最常使用的容器Tomcat为列来介绍以下两个知识点:Spring Boot是怎么整合启动Tomcat容器的;在Spring Boot中,怎么进行Tomcat的深度配置。Spring Boot整合启动Tomcat的流程对于看源代码,每个人都有...

weixin_42515990的博客 1735

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

四,分析Spring Boot底层机制(Tomcat 启动分析+Spring容器初始化+Tomcat如何关联 Spring 容器) 以及个人编写启动 Tomcat

在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。

weixin_61635597的博客 2906

Spring Boot 外置Tomcat启动原理

SPI机制装配SpringServletContainerInitializer // 注入WebApplicationInitializer @HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerIniti...

Forrest Gump的博客 537

Spring Boot 内嵌Tomcat启动原理

1、Tomcat的自动装配 WebServerFactory自动配置类:负责创建Tomcat、Netty、Jetty等 org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration @Configuration @ConditionalOnWebAppl...

Forrest Gump的博客 1205

Spring Boot 应用使用tomcat启动实现及原理

综上所述,我们可以得出结论,在servlet容器(tomcat)启动时,会调用SPI的相关逻辑调用到spring提供的实现类SpringServletContainerInitializer在该类的实现方法onStartup时,会把该类上注解中WebApplicationInitializer 接口的实现类传递给该方法的参数(webAppInitializerClasses)

qq_40270466的博客 1750

Spring Boot内嵌Tomcat启动

之前在Spring Boot启动过程(二)提到过createEmbeddedServletContainer创建了内嵌的Servlet容器,我用的是默认的Tomcat。 private void createEmbeddedServletContainer() { EmbeddedServletContainer localContainer = this.embe...

u014368614的博客 1392

Spring Boot 内置 Tomcat 启动原理:彻底搞懂“自动启动”的魔法

本文深入解析了SpringBoot内置Tomcat的启动机制,从依赖引入到自动配置,再到生命周期同步。通过ServletWebServerFactoryAutoConfiguration自动创建TomcatServletWebServerFactory,在Spring容器刷新时触发createWebServer()方法,最终启动原生Tomcat实例。关键点在于TomcatStarter作为桥梁,将Spring组件动态注册到Tomcat的ServletContext中。文章还介绍了三种定制方式:配置文件、编程

油墨香^-^的博客 1494

Spring Boot:内置tomcat启动和外部tomcat部署总结

下面举一些常用的例子。因为SpringBootServletInitializer需要依赖 javax.servlet,而tomcat-embed-jasper下面的tomcat-embed-core中就有这个javax.servlet,如果没用provided,最终打好的war里面会有servlet-api这个jar,这样就会跟tomcat本身的冲突了。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器以及提供,就不需要Maven重复地引入一遍。

m0_61083409的博客 1237

Spring Boot揭秘:一个JAR包如何神奇地启动内嵌Tomcat?

Spring Boot可执行JAR包通过巧妙设计实现内嵌Tomcat的一键启动。其核心机制包括:1) 特殊的JAR结构通过JarLauncher启动;2) 分层类加载器加载应用和依赖;3) SpringApplication在刷新上下文时自动创建Tomcat实例;4) 条件化自动配置动态判断Web环境。整个过程体现了约定优于配置的理念,开发者只需关注main方法,框架自动处理容器集成、Servlet注册等复杂逻辑,实现从传统WAR部署到轻量JAR的范式转变。

张小洛的BOLG 1469

spring boot 启动tomcat过程

从SpringApplication run方法开始 public ConfigurableApplicationContext run(String... args) { 、、、 try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); Config...

tszxlzc的专栏 231
上一篇: 70道Spring面试题,你能答对多少?(附答案)建议收藏!
下一篇: 东问西问,终于揭开腾讯面试的真面目!(一、二、三面)
Java_Yhua
博客等级 码龄6年 51粉丝 75原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值