嵌入式Servlet容器自动配置原理:
在spring-boot自动配置包中,有一个web模块,里边有一个嵌入式自动配置容器的配置:ServletWebServerFactoryAutoConfiguration
于此模型概念,在一个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。
**
* 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,这里与properties中serverProperties配置联系,解释了为什么配置文件也可修改servlet容器配置
@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是一个针对ServletWebServerFactory进行配置的配置类。它通过检测应用classpath存在的类,从而判断当前应用要使用哪个Servlet容器:Tomcat,Jetty还是Undertow。检测出来之后,定义相应的Servlet Web服务器工厂组件bean