本文主要介绍
1. Spring Boot内置Tomcat启动原理;
2. 切换Spring Boot默认Servlet容器;
1. Spring Boot内置Tomcat启动原理;
1. Spring Boot默认支持Tomcat,Jetty,和Undertow作为底层容器;在无特殊配置时,底层容器默认为Tomcat(spring-boot-starter-web中默认依赖Tomcat, 具体见下文)
在spring-boot-autoconfigure下的META-INF/spring.factories中key为 org.springframework.boot.autoconfigure.EnableAutoConfiguration
配置的自动装配类信息包含org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
@Configuration(proxyBeanMethods = false) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @ConditionalOnClass(ServletRequest.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(ServerProperties.class) @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration {...................
(默认支持Tomcat,Jetty,和Undertow作为底层容器)
@Configuration(proxyBeanMethods = false) class ServletWebServerFactoryConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @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(); factory.getTomcatConnectorCustomizers() .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatContextCustomizers() .addAll(contextCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatProtocolHandlerCustomizers() .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } /** * Nested configuration if Jetty is being used. */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) static class EmbeddedJetty { @Bean JettyServletWebServerFactory JettyServletWebServerFactory( ObjectProvider<JettyServerCustomizer> serverCustomizers) { JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } /** * Nested configuration if Undertow is being used. */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) static class EmbeddedUndertow { @Bean UndertowServletWebServerFactory undertowServletWebServerFactory( ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers, ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) { UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); factory.getDeploymentInfoCustomizers() .addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList())); factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList())); return factory; } } }
默认情况下 EmbeddedTomcat 条件注解会生效会创建 TomcatServletWebServerFactory 的实例对象而 EmbeddedJetty 及 EmbeddedUndertow 的条件注解将不生效;
在TomcatServletWebServerFactory 中存在getWebServer方法,此方法会创建及启动一个Tomcat
public WebServer getWebServer(ServletContextInitializer... initializers) { if (this.disableMBeanRegistry) { Registry.disableRegistry(); } //实例化一个Tomcat Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); //设置Tomcat的工作临时目录 tomcat.setBaseDir(baseDir.getAbsolutePath()); //默认使用Http11NioProtocal实例化Connector Connector connector = new Connector(this.protocol); connector.setThrowOnFailure(true); //给Service添加Connector tomcat.getService().addConnector(connector); customizeConnector(connector); tomcat.setConnector(connector); //关闭热部署 tomcat.getHost().setAutoDeploy(false); //配置Engine configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); // 实例化TomcatWebServer时会将DispatcherServlet以及一些Filter添加到Tomcat中 return getTomcatWebServer(tomcat); }
getTomcatWebServer(tomcat) 方法最终会启动Tomcate
this.tomcat.start();
2. 在Spring Boot 启动过程中,刷新上下文(refreshContext)时 会通过上下文对象ConfigurableApplicationContext调用Spring的核心方法refresh;
在AbstractApplicationContext.fresh中通过
A.invokeBeanFactoryPostProcessors(beanFactory)方法会加载在META-INF下spring.facories下key为 EnableAutoConfiguration全限定类名的值,并将类信息存入IOC容器;
B.onRefresh()方法调用TomcatServletWebServerFactory 的 getWebServer方法,创建及启动一个Tomcat;
2. 切换Spring Boot默认Servlet容器
1. SpringBoot默认Servlet容器为Tomcat
在spring-boot-starter-web依赖中
<artifactId>spring-boot-starter-web</artifactId> <name>Spring Boot Web Starter</name> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <exclusions> <exclusion> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-el</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> </dependencies>
2. 切换Spring Boot默认Servlet容器为Jetty
Spring Boot 官方提供了Servlet容器Starter方式:Spring Boot Starters
包含
spring-boot-starter-tomcat (默认)
spring-boot-starter-undertow
spring-boot-starter-jetty
切换Spring Boot默认Servlet容器,只需将默认的tomcat 移除,引入需要切换的容器的starter
1.移除默认的Tomcat 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
2. 引入 jetty 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>