本文结论
源码基于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。
自动配置类:ServletWebServerFactoryAutoConfiguration
在spring-boot-autoconfigure-2.6.6.jar这个包中的spring.factories文件内,配置了大量的自动配置类,其中就包括自动配置tomcat的自动配置类: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 {
. . . . . .
}
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 )
@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;
}
}
}
对于另外的EmbeddedJetty和EmbeddedUndertow,逻辑类似,都是判断项目依赖中是否有Jetty和Undertow的依赖,如果有,那么对应在Spring容器中就会存在JettyServletWebServerFactory类型的Bean、或者存在UndertowServletWebServerFactory类型的Bean。
TomcatServletWebServerFactory的作用:获取WebServer对象
TomcatServletWebServerFactory他实现了ServletWebServerFactory这个接口。 ServletWebServerFactory接口内部只有一个方法是获取WebServer对象。
WebServer拥有启动、停止、获取端口等方法,就会发现WebServer其实指的就是Tomcat、Jetty、Undertow。
而TomcatServletWebServerFactory就是用来生成Tomcat所对应的WebServer对象,具体一点就是TomcatWebServer对象,并且在生成TomcatWebServer对象时会把Tomcat给启动起来。 在源码中,调用TomcatServletWebServerFactory对象的getWebServer()方法时就会启动Tomcat。
public WebServer getWebServer ( ServletContextInitializer . . . initializers) {
if ( this . disableMBeanRegistry) {
Registry . disableRegistry ( ) ;
}
Tomcat tomcat = new Tomcat ( ) ;
File baseDir = ( this . baseDirectory != null ) ? this . baseDirectory : createTempDir ( "tomcat" ) ;
tomcat. setBaseDir ( baseDir. getAbsolutePath ( ) ) ;
for ( LifecycleListener listener : this . serverLifecycleListeners) {
tomcat. getServer ( ) . addLifecycleListener ( listener) ;
}
Connector connector = new Connector ( this . protocol) ;
connector. setThrowOnFailure ( true ) ;
tomcat. getService ( ) . addConnector ( connector) ;
customizeConnector ( connector) ;
tomcat. setConnector ( connector) ;
tomcat. getHost ( ) . setAutoDeploy ( false ) ;
configureEngine ( tomcat. getEngine ( ) ) ;
for ( Connector additionalConnector : this . additionalTomcatConnectors) {
tomcat. getService ( ) . addConnector ( additionalConnector) ;
}
prepareContext ( tomcat. getHost ( ) , initializers) ;
return getTomcatWebServer ( tomcat) ;
}
spring boot启动的时候启动tomcat
SpringBoot的启动过程中,会调用核心的refresh方法,内部会执行onRefresh()方法,onRefresh()方法是一个模板方法,他会执行会执行子类ServletWebServerApplicationContext的onRefresh()方法。
protected void onRefresh ( ) {
super . onRefresh ( ) ;
try {
createWebServer ( ) ;
}
catch ( Throwable ex) {
throw new ApplicationContextException ( "Unable to start web server" , ex) ;
}
}
这个方法会调用createWebServer()方法。
private void createWebServer ( ) {
. . . . . .
ServletWebServerFactory factory = getWebServerFactory ( ) ;
this . webServer = factory. getWebServer ( getSelfInitializer ( ) ) ;
. . . . . .
}
getWebServerFactory控制项目组有且只能有一个web容器!
protected ServletWebServerFactory getWebServerFactory ( ) {
String [ ] beanNames = getBeanFactory ( ) . getBeanNamesForType ( ServletWebServerFactory . class ) ;
if ( beanNames. length == 0 ) {
throw new ApplicationContextException ( "Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean." ) ;
}
if ( beanNames. length > 1 ) {
throw new ApplicationContextException ( "Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils . arrayToCommaDelimitedString ( beanNames) ) ;
}
return getBeanFactory ( ) . getBean ( beanNames[ 0 ] , ServletWebServerFactory . class ) ;
}
获取tomcat的配置
自动配置类ServletWebServerFactoryAutoConfiguration上除了import三个web容器,还import了BeanPostProcessorsRegistrar。 BeanPostProcessorsRegistrar实现了ImportBeanDefinitionRegistrar,所以他会在spring启动的时候调用registerBeanDefinitions方法。 registerBeanDefinitions会注册一个Bean:webServerFactoryCustomizerBeanPostProcessor。
public void registerBeanDefinitions ( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if ( this . beanFactory == null ) {
return ;
}
registerSyntheticBeanIfMissing ( registry, "webServerFactoryCustomizerBeanPostProcessor" ,
WebServerFactoryCustomizerBeanPostProcessor . class ,
WebServerFactoryCustomizerBeanPostProcessor :: new ) ;
registerSyntheticBeanIfMissing ( registry, "errorPageRegistrarBeanPostProcessor" ,
ErrorPageRegistrarBeanPostProcessor . class , ErrorPageRegistrarBeanPostProcessor :: new ) ;
}
webServerFactoryCustomizerBeanPostProcessor实现了BeanPostProcessor,所以他会在启动的时候调用postProcessBeforeInitialization方法。
private void postProcessBeforeInitialization ( WebServerFactory webServerFactory) {
LambdaSafe . callbacks ( WebServerFactoryCustomizer . class , getCustomizers ( ) , webServerFactory)
. withLogger ( WebServerFactoryCustomizerBeanPostProcessor . class )
. invoke ( ( customizer) -> customizer. customize ( webServerFactory) ) ;
}
postProcessBeforeInitialization中会调用WebServerFactoryCustomizer类customize方法,在系统中的唯一实现:ServletWebServerFactoryCustomizer的customize方法。 customize把配置中的内容设置到ConfigurableServletWebServerFactory对象中。他的实现TomcatServletWebServerFactory在启动的时候就会有值!
@Override
public void customize ( ConfigurableServletWebServerFactory factory) {
PropertyMapper map = PropertyMapper . get ( ) . alwaysApplyingWhenNonNull ( ) ;
map. from ( this . serverProperties:: getPort ) . to ( factory:: setPort ) ;
map. from ( this . serverProperties:: getAddress ) . to ( factory:: setAddress ) ;
map. from ( this . serverProperties. getServlet ( ) :: getContextPath ) . to ( factory:: setContextPath ) ;
map. from ( this . serverProperties. getServlet ( ) :: getApplicationDisplayName ) . to ( factory:: setDisplayName ) ;
map. from ( this . serverProperties. getServlet ( ) :: isRegisterDefaultServlet ) . to ( factory:: setRegisterDefaultServlet ) ;
map. from ( this . serverProperties. getServlet ( ) :: getSession ) . to ( factory:: setSession ) ;
map. from ( this . serverProperties:: getSsl ) . to ( factory:: setSsl ) ;
map. from ( this . serverProperties. getServlet ( ) :: getJsp ) . to ( factory:: setJsp ) ;
map. from ( this . serverProperties:: getCompression ) . to ( factory:: setCompression ) ;
map. from ( this . serverProperties:: getHttp2 ) . to ( factory:: setHttp2 ) ;
map. from ( this . serverProperties:: getServerHeader ) . to ( factory:: setServerHeader ) ;
map. from ( this . serverProperties. getServlet ( ) :: getContextParameters ) . to ( factory:: setInitParameters ) ;
map. from ( this . serverProperties. getShutdown ( ) ) . to ( factory:: setShutdown ) ;
for ( WebListenerRegistrar registrar : this . webListenerRegistrars) {
registrar. register ( factory) ;
}
if ( ! CollectionUtils . isEmpty ( this . cookieSameSiteSuppliers) ) {
factory. setCookieSameSiteSuppliers ( this . cookieSameSiteSuppliers) ;
}
}
ServletWebServerFactoryCustomizer这个Bean是哪里的?
在我们自动配置类ServletWebServerFactoryAutoConfiguration中定义。
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer ( ServerProperties serverProperties, ObjectProvider < WebListenerRegistrar > webListenerRegistrars, ObjectProvider < CookieSameSiteSupplier > cookieSameSiteSuppliers) {
return new ServletWebServerFactoryCustomizer ( serverProperties, webListenerRegistrars. orderedStream ( ) . collect ( Collectors . toList ( ) ) , cookieSameSiteSuppliers. orderedStream ( ) . collect ( Collectors . toList ( ) ) ) ;
}