目录 本文结论 spring-boot-starter-web内部有什么? TomcatServletWebServerFactory的作用:获取WebServer对象 spring boot启动的时候启动tomcat 获取tomcat的配置 ServletWebServerFactoryCustomizer这个Bean是哪里的? 从源码层面理解spring boot的默认web容器,以及他们是如何关联起来的。
本文结论 源码基于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()));
}