Spring Boot 自动配置 : ServletWebSer
概述
Spring Boot
对所支持的Servlet Web
服务器实现做了建模抽象:
Servlet 容器类型 |
WebServer 模型接口 |
WebServer 工厂实现类 |
---|---|---|
Tomcat |
TomcatWebServer |
TomcatServletWebServerFactory |
Jetty |
JettyWebServer |
JettyServletWebServerFactory |
Undertow |
UndertowWebServer |
UndertowServletWebServerFactory |
基于此模型概念,在一个Servlet Web
应用中,Spring Boot
会使用上表中所说的WebServer
工厂组件生成相应的WebServer
实例。而这里的WebServer
工厂组件又是从哪里来的呢 ? 这就是自动配置类ServletWebServerFactoryAutoConfiguration
的任务了。
自动配置类ServletWebServerFactoryAutoConfiguration
首先通过注解声明自己的生效条件:
- 类
ServletRequest
存在于classpath
上时才生效,也就是要求javax.servlet-api
包必须被引用; - 当前应用必须是
Spring MVC
应用才生效;
在以上条件被满足时,ServletWebServerFactoryAutoConfiguration
引入了如下三个配置类 :
EmbeddedTomcat
EmbeddedJetty
EmbeddedUndertow
这三个配置类是ServletWebServerFactoryConfiguration
的嵌套配置类,它们会分别检测classpath
上存在的类,从而判断当前应用使用的是Tomcat/Jetty/Undertow
中的哪一个Servlet Web
服务器,从而决定定义相应的工厂组件bean
: TomcatServletWebServerFactory
/JettyServletWebServerFactory
/UndertowServletWebServerFactory
。
源代码
源代码版本 : spring-boot-autoconfigure-2.1.3.RELEASE
ServletWebServerFactoryAutoConfiguration
package org.springframework.boot.autoconfigure.web.servlet;
// 省略 import 行
/**
* EnableAutoConfiguration Auto-configuration for servlet web servers.
*
*/
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
// 仅在类 ServletRequest 存在于 classpath 上时才生效
@ConditionalOnClass(ServletRequest.class)
// 仅在当前应用是 Servlet Web 应用时才生效
@ConditionalOnWebApplication(type = Type.SERVLET)
// 确保前缀为 server 的配置参数加载到 bean ServerProperties
@EnableConfigurationProperties(ServerProperties.class)
// 1. 导入 ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar 以注册
// BeanPostProcessor : WebServerFactoryCustomizerBeanPostProcessor 和
// ErrorPageRegistrarBeanPostProcessor
// 2. 导入 EmbeddedTomcat/EmbeddedJetty/EmbeddedUndertow 这三个属于
// ServletWebServerFactoryConfiguration 的嵌套配置类,这三个配置类会分别检测
// classpath上存在的类,从而判断当前应用使用的是 Tomcat/Jetty/Undertow,
// 从而决定定义哪一个 Servlet Web服务器的工厂 bean :
// TomcatServletWebServerFactory/JettyServletWebServerFactory/UndertowServletWebServerFactory
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
// 定义 bean ServletWebServerFactoryCustomizer
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
// 针对当前Servlet容器是Tomcat时定义该 bean,用于定制化 TomcatServletWebServerFactory
@Bean
// 仅在类 org.apache.catalina.startup.Tomcat 存在于 classpath 上时才生效
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
/**
* Registers a WebServerFactoryCustomizerBeanPostProcessor. Registered via
* ImportBeanDefinitionRegistrar for early registration.
* 这是一个 ImportBeanDefinitionRegistrar, 它会向容器注入两个 BeanPostProcessor :
* 1. WebServerFactoryCustomizerBeanPostProcessor
* 该 BeanPostProcessor 会搜集容器中所有的 WebServerFactoryCustomizer,对当前应用所采用的
* WebServerFactory 被初始化前进行定制
* 2. ErrorPageRegistrarBeanPostProcessor
* 该 BeanPostProcessor 会搜集容器中所有的 ErrorPageRegistrar,添加到当前应用所采用的
* ErrorPageRegistry 中,实际上,这里的 ErrorPageRegistry 会是 ConfigurableWebServerFactory,
* 具体实现上来讲,是一个 ConfigurableTomcatWebServerFactory,ConfigurableJettyWebServerFactory
* 或者 ConfigurableUndertowWebServerFactory,分别对应 Tomcat, Jetty, Undertow 这三种
* Servlet Web 容器的工厂类
*/
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof ConfigurableListableBeanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
registerSyntheticBeanIfMissing(registry,
"webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
String name, Class<?> beanClass) {
if (ObjectUtils.isEmpty(
this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
}
ServletWebServerFactoryConfiguration
ServletWebServerFactoryConfiguration
是一个针对ServletWebServerFactory
进行配置的配置类。它通过检测应用classpath
存在的类,从而判断当前应用要使用哪个Servlet
容器:Tomcat
,Jetty
还是Undertow
。检测出来之后,定义相应的Servlet Web
服务器工厂组件bean
:
Servlet
容器类型
WebServerFactory
实现类
Tomcat
TomcatServletWebServerFactory
Jetty
JettyServletWebServerFactory
Undertow
UndertowServletWebServerFactory
注意,以上三个实现类都继承自抽象基类AbstractServletWebServerFactory
,实现了接口WebServerFactory
,ErrorPageRegistry
。该特征会被WebServerFactoryCustomizerBeanPostProcessor
和ErrorPageRegistrarBeanPostProcessor
使用,用于对WebServerFactory
进行定制化,以及设置相应的错误页面。
package org.springframework.boot.autoconfigure.web.servlet;
// 省略 import 行
/**
* Configuration classes for servlet web servers
*
* Those should be @Import in a regular auto-configuration class to guarantee
* their order of execution.
*
*/
@Configuration
class ServletWebServerFactoryConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
return new UndertowServletWebServerFactory();
}
}
}