【Spring boot】整合tomcat底层原理

本文结论

  • 源码基于spring boot2.6.6
  • 项目的pom.xml中存在spring-boot-starter-web的时候,在项目启动时候就会自动启动一个Tomcat 。
  • 自动配置类ServletWebServerFactoryAutoConfiguration找到系统中的所有web容器 。我们以tomcat为主 。
  • 构建TomcatServletWebServerFactory的bean 。
  • SpringBoot的启动过程中,会调用核心的refresh方法,内部会执行onRefresh()方法,onRefresh()方法是一个模板方法,他会执行会执行子类ServletWebServerApplicationContext的onRefresh()方法 。
  • onRefresh()方法中调用getWebServer启动web容器 。
spring-boot-starter-web内部有什么?
  • 在spring-boot-starter-web这个starter中,其实内部间接的引入了spring-boot-starter-tomcat这个starter,这个spring-boot-starter-tomcat又引入了tomcat-embed-core依赖,所以只要我们项目中依赖了spring-boot-starter-web就相当于依赖了Tomcat 。

【Spring boot】整合tomcat底层原理

文章插图

【Spring boot】整合tomcat底层原理

文章插图
自动配置类:ServletWebServerFactoryAutoConfiguration
  • 在spring-boot-autoconfigure-2.6.6.jar这个包中的spring.factories文件内,配置了大量的自动配置类,其中就包括自动配置tomcat的自动配置类:ServletWebServerFactoryAutoConfiguration

【Spring boot】整合tomcat底层原理

文章插图
自动配置类的代码如下// full模式@Configuration(proxyBeanMethods = false)// 配置类解析顺序@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)// 条件注解:表示项目依赖中要有ServletRequest类(server api)@ConditionalOnClass(ServletRequest.class)// 表示项目应用类型得是SpringMVC(在启动过程中获取的SpringBoot应用类型)@ConditionalOnWebApplication(type = Type.SERVLET)// 读取server下的配置文件@EnableConfigurationProperties(ServerProperties.class)// import具体的加载配置的类和具体web实现容器@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })public class ServletWebServerFactoryAutoConfiguration { ......}
  • ServletRequest是存在于tomcat-embed-core-9.0.60.jar中的的一个类,所以@ConditionalOnClass(ServletRequest.clas s)会满足 。
  • spring-boot-starter-web中,间接的引入了spring-web、spring-webmvc等依赖,所以@ConditionalOnWebApplication(type = Type.SERVLET)条件满足 。
  • 上面的俩个条件都满足,所以spring回去解析这个配置类,在解析过程中会发现他import了三个类!我们重点关注EmbeddedTomcat 。其他俩个的内部条件注解不满足!
@Configuration(proxyBeanMethods = false)// tomcat内部的类,肯定都存在@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })// 程序员如果自定义了ServletWebServerFactory的Bean,那么这个Bean就不加载 。@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)static class EmbeddedTomcat {    @Bean    TomcatServletWebServerFactory tomcatServletWebServerFactory(        ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,        ObjectProvider<TomcatContextCustomizer> contextCustomizers,        ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();            // orderedStream()调用时会去Spring容器中找到TomcatConnectorCustomizer类型的Bean,默认是没有的,程序员可以自己定义 。这个Bean可以设置一些tomcat的配置,比如端口、协议...            // TomcatConnectorCustomizer:是用来配置Tomcat中的Connector组件的            factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));            // TomcatContextCustomizer:是用来配置Tomcat中的Context组件的            factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));            // TomcatProtocolHandlerCustomizer:是用来配置Tomcat中的ProtocolHandler组件的            factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));            return factory;        }    }}

经验总结扩展阅读