createWebServer
SpringBoot 会从ServletWebServerApplicationContext 中启动 createWebServer 方法,该方法会根据当前导入的Servlet类型创建相应的ServletWeb服务工厂:Jetty、Tomcat 或 Undertow。
为啥这里没有Netty?
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
创建tomcatServer
如何获取getWebServerFactory?
这里的要get的Bean名字为:tomcatServletWebServerFactory
由于tomcatServletWebServerFactory必然为单例,首次get时必然需要create
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
create之后需要初始化
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
在AbstractAutowireCapableBeanFactory类中:
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//调用初始方法的前置处理器
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//调用初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//初始化方法的后置处理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
在调用初始化器的前置方法期间,需要获得并调用tomcatWebServerFactoryCustomizer,即tomcat网络服务器工厂的定制化器。
初次尝试Get必然失败需要Creat 这个定制化器。
在EmbeddedWebServerFactoryCustomizerAutoConfiguration 类中调用如下方法:
/**
* Nested configuration if Tomcat is being used.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
public static class TomcatWebServerFactoryCustomizerConfiguration {
@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
}
使用合并后的后置处理器来修饰这个定制器(tomcatWebServerFactoryCustomizer)
来到WebServerFactoryCustomizerBeanPostProcessor类中的初始化方法前置处理器
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
.invoke((customizer) -> customizer.customize(webServerFactory));
}
customize方法定制化webServerFactory
这个处理器会调用定制化器的customize方法定制化webServerFactory:
@Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
ServerProperties properties = this.serverProperties;
ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
PropertyMapper propertyMapper = PropertyMapper.get();
propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory);
propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull().as(Duration::getSeconds)
.as(Long::intValue).to(factory::setBackgroundProcessorDelay);
customizeRemoteIpValve(factory);
ServerProperties.Tomcat.Threads threadProperties = tomcatProperties.getThreads();
propertyMapper.from(threadProperties::getMax).when(this::isPositive)
.to((maxThreads) -> customizeMaxThreads(factory, threadProperties.getMax()));
propertyMapper.from(threadProperties::getMinSpare).when(this::isPositive)
.to((minSpareThreads) -> customizeMinThreads(factory, minSpareThreads));
propertyMapper.from(this.serverProperties.getMaxHttpHeaderSize()).whenNonNull().asInt(DataSize::toBytes)
.when(this::isPositive)
.to((maxHttpHeaderSize) -> customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize));
propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull().asInt(DataSize::toBytes)
.to((maxSwallowSize) -> customizeMaxSwallowSize(factory, maxSwallowSize));
propertyMapper.from(tomcatProperties::getMaxHttpFormPostSize).asInt(DataSize::toBytes)
.when((maxHttpFormPostSize) -> maxHttpFormPostSize != 0)
.to((maxHttpFormPostSize) -> customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize));
propertyMapper.from(tomcatProperties::getAccesslog).when(ServerProperties.Tomcat.Accesslog::isEnabled)
.to((enabled) -> customizeAccessLog(factory));
propertyMapper.from(tomcatProperties::getUriEncoding).whenNonNull().to(factory::setUriEncoding);
propertyMapper.from(tomcatProperties::getConnectionTimeout).whenNonNull()
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
propertyMapper.from(tomcatProperties::getMaxConnections).when(this::isPositive)
.to((maxConnections) -> customizeMaxConnections(factory, maxConnections));
propertyMapper.from(tomcatProperties::getAcceptCount).when(this::isPositive)
.to((acceptCount) -> customizeAcceptCount(factory, acceptCount));
propertyMapper.from(tomcatProperties::getProcessorCache)
.to((processorCache) -> customizeProcessorCache(factory, processorCache));
propertyMapper.from(tomcatProperties::getRelaxedPathChars).as(this::joinCharacters).whenHasText()
.to((relaxedChars) -> customizeRelaxedPathChars(factory, relaxedChars));
propertyMapper.from(tomcatProperties::getRelaxedQueryChars).as(this::joinCharacters).whenHasText()
.to((relaxedChars) -> customizeRelaxedQueryChars(factory, relaxedChars));
customizeStaticResources(factory);
customizeErrorReportValve(properties.getError(), factory);
}
webServerFactory定制化=webServer定制化
这个webServerFactory实现了ServletWebServerFactory的getWebServer方法:
所以可通过实现WebServerFactoryCustomizer接口的方式,实现customize方法来修饰tomcatServer
启动流程总结:
-
SpringBoot 根据到导入的依赖信息,自动创建相应的webServerFactoryCustomizer(工厂定制器)
-
web服务工厂定制器的后置处理器类中的方法会收集所有实现了webServerFactoryCustomizer接口的定制器,并依次调用这些定制器的customize方法,去定制化servlet容器工厂。
-
嵌入式的Servlet容器工厂调用getWebServer方法创建tomcat容器(tomcatServer),初始化容器。
定制化总结:
-
由于Customizer的大量信息都是从Properties中加载的,因此可以通过修改全局配置文件application.properties,来达到定制化的目的。
-
可以实现WebServerFactoryCustomizer接口,并重写其customize方法达到定制化目的。