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)
这个处理器会调用定制化器的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实现了ServletWebServerFactory的getWebServer方法: 所以可通过实现WebServerFactoryCustomizer接口的方式,实现customize方法来修饰tomcatServer
SpringBoot 根据到导入的依赖信息,自动创建相应的webServerFactoryCustomizer(工厂定制器)
web服务工厂定制器的后置处理器类中的方法会收集所有实现了webServerFactoryCustomizer接口的定制器,并依次调用这些定制器的customize方法,去定制化servlet容器工厂。
嵌入式的Servlet容器工厂调用getWebServer方法创建tomcat容器(tomcatServer),初始化容器。
由于Customizer的大量信息都是从Properties中加载的,因此可以通过修改全局配置文件application.properties,来达到定制化的目的。
可以实现WebServerFactoryCustomizer接口,并重写其customize方法达到定制化目的。
