美文网首页
Spring Boot 自动配置 : ServletWebSer

Spring Boot 自动配置 : ServletWebSer

作者: jeffrey_hjf | 来源:发表于2022-01-28 16:23 被阅读0次

    概述

    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();
            }
    
        }
    
    }

    相关文章

      网友评论

          本文标题:Spring Boot 自动配置 : ServletWebSer

          本文链接:https://www.haomeiwen.com/subject/yaltkrtx.html