Spring Boot 自动配置 : ServletWebSer

2022-01-28  本文已影响0人  jeffrey_hjf

概述

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首先通过注解声明自己的生效条件:

  1. ServletRequest 存在于 classpath 上时才生效,也就是要求javax.servlet-api包必须被引用;
  2. 当前应用必须是Spring MVC应用才生效;

在以上条件被满足时,ServletWebServerFactoryAutoConfiguration引入了如下三个配置类 :

  1. EmbeddedTomcat
  2. EmbeddedJetty
  3. 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。该特征会被WebServerFactoryCustomizerBeanPostProcessorErrorPageRegistrarBeanPostProcessor使用,用于对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();
        }

    }

}
上一篇下一篇

猜你喜欢

热点阅读