https://blog.csdn.net/caychen/article/details/80346331

其中EmbeddedServletContainerAutoConfiguration是嵌入式Servlet容器的自动配置类,该类在spring-boot-autoconfigure-xxx.jar中的web模块可以找到。

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
​
​
​
@Configuration
​
​
​
@ConditionalOnWebApplication
​
​
​
@Import(BeanPostProcessorsRegistrar.class)
​
​
​
public class EmbeddedServletContainerAutoConfiguration {
​
​
​
 
​
​
​
    @Configuration
​
​
​
    @ConditionalOnClass({ Servlet.class, Tomcat.class })
​
​
​
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
​
​
​
    public static class EmbeddedTomcat {
​
​
​
 
​
​
​
        @Bean
​
​
​
        public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
​
​
​
            return new TomcatEmbeddedServletContainerFactory();
​
​
​
        }
​
​
​
    }
​
​
​
    
​
​
​
    @Configuration
​
​
​
    @ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
​
​
​
            WebAppContext.class })
​
​
​
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
​
​
​
    public static class EmbeddedJetty {
​
​
​
 
​
​
​
        @Bean
​
​
​
        public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
​
​
​
            return new JettyEmbeddedServletContainerFactory();
​
​
​
        }
​
​
​
 
​
​
​
    }
​
​
​
    
​
​
​
    @Configuration
​
​
​
    @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
​
​
​
    @ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
​
​
​
    public static class EmbeddedUndertow {
​
​
​
 
​
​
​
        @Bean
​
​
​
        public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
​
​
​
            return new UndertowEmbeddedServletContainerFactory();
​
​
​
        }
​
​
​
 
​
​
​
    }
​
​
​
    
​
​
​
    //other code...
​
​
​
}

在这个自动配置类中配置了三个容器工厂的Bean,分别是:

  • *TomcatEmbeddedServletContainerFactory*

  • *JettyEmbeddedServletContainerFactory*

  • *UndertowEmbeddedServletContainerFactory*

    这里以大家熟悉的Tomcat为例,首先Spring Boot会判断当前环境中是否引入了Servlet和Tomcat依赖,并且当前容器中没有自定义的EmbeddedServletContainerFactory的情况下,则创建Tomcat容器工厂。其他Servlet容器工厂也是同样的道理。

1)、EmbeddedServletContainerFactory:嵌入式Servlet容器工厂

public interface EmbeddedServletContainerFactory {
​
​
​
 
​
​
​
    EmbeddedServletContainer getEmbeddedServletContainer(
​
​
​
            ServletContextInitializer... initializers);
​
​
​
}

内部只有一个方法,用于获取嵌入式的Servlet容器。

该工厂接口主要有三个实现类,分别对应三种嵌入式Servlet容器的工厂类,如图所示:

img

2)、EmbeddedServletContainer:嵌入式Servlet容器

同样道理,对应三种嵌入式Servlet容器,如图所示:

img

3)、以Tomcat容器工厂TomcatEmbeddedServletContainerFactory类为例:

public class TomcatEmbeddedServletContainerFactory
​
​
​
        extends AbstractEmbeddedServletContainerFactory implements ResourceLoaderAware {
​
​
​
    
​
​
​
    //other code...
​
​
​
    
​
​
​
    @Override
​
​
​
    public EmbeddedServletContainer getEmbeddedServletContainer(
​
​
​
            ServletContextInitializer... initializers) {
​
​
​
        //创建一个Tomcat
​
​
​
        Tomcat tomcat = new Tomcat();
​
​
​
        
​
​
​
        //配置Tomcat的基本环节
​
​
​
        File baseDir = (this.baseDirectory != null ? this.baseDirectory
​
​
​
                : createTempDir("tomcat"));
​
​
​
        tomcat.setBaseDir(baseDir.getAbsolutePath());
​
​
​
        Connector connector = new Connector(this.protocol);
​
​
​
        tomcat.getService().addConnector(connector);
​
​
​
        customizeConnector(connector);
​
​
​
        tomcat.setConnector(connector);
​
​
​
        tomcat.getHost().setAutoDeploy(false);
​
​
​
        configureEngine(tomcat.getEngine());
​
​
​
        for (Connector additionalConnector : this.additionalTomcatConnectors) {
​
​
​
            tomcat.getService().addConnector(additionalConnector);
​
​
​
        }
​
​
​
        prepareContext(tomcat.getHost(), initializers);
​
​
​
        
​
​
​
        //包装tomcat对象,返回一个嵌入式Tomcat容器,内部会启动该tomcat容器
​
​
​
        return getTomcatEmbeddedServletContainer(tomcat);
​
​
​
    }
​
​
​
}

看看TomcatEmbeddedServletContainerFactory#getTomcatEmbeddedServletContainer函数:

protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
​
​
​
    Tomcat tomcat) {
​
​
​
    return new TomcatEmbeddedServletContainer(tomcat, getPort() >= 0);
​
​
​
}

该函数很简单,就是来创建Tomcat容器并返回。

看看TomcatEmbeddedServletContainer类定义:

public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer {
​
​
​
 
​
​
​
    public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {
​
​
​
        Assert.notNull(tomcat, "Tomcat Server must not be null");
​
​
​
        this.tomcat = tomcat;
​
​
​
        this.autoStart = autoStart;
​
​
​
        
​
​
​
        //初始化嵌入式Tomcat容器,并启动Tomcat
​
​
​
        initialize();
​
​
​
    }
​
​
​
    
​
​
​
    private void initialize() throws EmbeddedServletContainerException {
​
​
​
        TomcatEmbeddedServletContainer.logger
​
​
​
                .info("Tomcat initialized with port(s): " + getPortsDescription(false));
​
​
​
        synchronized (this.monitor) {
​
​
​
            try {
​
​
​
                addInstanceIdToEngineName();
​
​
​
                try {
​
​
​
                    final Context context = findContext();
​
​
​
                    context.addLifecycleListener(new LifecycleListener() {
​
​
​
 
​
​
​
                        @Override
​
​
​
                        public void lifecycleEvent(LifecycleEvent event) {
​
​
​
                            if (context.equals(event.getSource())
​
​
​
                                    && Lifecycle.START_EVENT.equals(event.getType())) {
​
​
​
                                // Remove service connectors so that protocol
​
​
​
                                // binding doesn't happen when the service is
​
​
​
                                // started.
​
​
​
                                removeServiceConnectors();
​
​
​
                            }
​
​
​
                        }
​
​
​
 
​
​
​
                    });
​
​
​
 
​
​
​
                    // Start the server to trigger initialization listeners
​
​
​
                      //启动tomcat
​
​
​
                    this.tomcat.start();
​
​
​
 
​
​
​
                    // We can re-throw failure exception directly in the main thread
​
​
​
                    rethrowDeferredStartupExceptions();
​
​
​
 
​
​
​
                    try {
​
​
​
                        ContextBindings.bindClassLoader(context, getNamingToken(context),
​
​
​
                                getClass().getClassLoader());
​
​
​
                    }
​
​
​
                    catch (NamingException ex) {
​
​
​
                        // Naming is not enabled. Continue
​
​
​
                    }
​
​
​
 
​
​
​
                    // Unlike Jetty, all Tomcat threads are daemon threads. We create a
​
​
​
                    // blocking non-daemon to stop immediate shutdown
​
​
​
                    startDaemonAwaitThread();
​
​
​
                }
​
​
​
                catch (Exception ex) {
​
​
​
                    containerCounter.decrementAndGet();
​
​
​
                    throw ex;
​
​
​
                }
​
​
​
            }
​
​
​
            catch (Exception ex) {
​
​
​
                stopSilently();
​
​
​
                throw new EmbeddedServletContainerException(
​
​
​
                        "Unable to start embedded Tomcat", ex);
​
​
​
            }
​
​
​
        }
​
​
​
    }
​
​
​
}

到这里就启动了嵌入式的Servlet容器,其他容器类似。

那么问题来了,我们对嵌入式容器的修改配置是如何生效的?

? 之前讲过可以通过修改ServerProperties相关配置或者自定义EmbeddedServletContainerCustomizer定制器两种方式来修改默认配置。而ServerProperties其实就是EmbeddedServletContainerCustomizer的子类,所以说到底还是EmbeddedServletContainerCustomizer起了修改的作用。

? 其实在EmbeddedServletContainerAutoConfiguration类上导入了一个BeanPostProcessorsRegistrar类:

@Import(BeanPostProcessorsRegistrar.class)

该类主要用于给容器导入组件,看定义:

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;
​
​
​
        }
​
​
​
        //注册了一个EmbeddedServletContainerCustomizerBeanPostProcessor后置处理器的Bean
​
​
​
        registerSyntheticBeanIfMissing(registry,
​
​
​
                                       "embeddedServletContainerCustomizerBeanPostProcessor",
​
​
​
                                       EmbeddedServletContainerCustomizerBeanPostProcessor.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);
​
​
​
        }
​
​
​
    }
​
​
​
 
​
​
​
}

后置处理器:在bean初始化前(创建完成,还未属性赋值),会执行初始化工作。

所以重点是在registerBeanDefinitions方法中向容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor类型的Bean:

public class EmbeddedServletContainerCustomizerBeanPostProcessor
​
​
​
        implements BeanPostProcessor, BeanFactoryAware {
​
​
​
 
​
​
​
    //初始化之前
​
​
​
    @Override
​
​
​
    public Object postProcessBeforeInitialization(Object bean, String beanName)
​
​
​
            throws BeansException {
​
​
​
        if (bean instanceof ConfigurableEmbeddedServletContainer) {
​
​
​
            postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
​
​
​
        }
​
​
​
        return bean;
​
​
​
    }
​
​
​
    
​
​
​
    private void postProcessBeforeInitialization(
​
​
​
            ConfigurableEmbeddedServletContainer bean) {
​
​
​
        //获取所有的定制器,调用每个定制器的customize方法,给Servlet容器进行属性赋值
​
​
​
        for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
​
​
​
            customizer.customize(bean);
​
​
​
        }
​
​
​
    }
​
​
​
    
​
​
​
    //从IOC容器中获取所有类型为EmbeddedServletContainerCustomizer的定制器
​
​
​
    private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
​
​
​
        if (this.customizers == null) {
​
​
​
            // Look up does not include the parent context
​
​
​
            this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
​
​
​
                //类型为EmbeddedServletContainerCustomizer的Bean
​
​
​
                    this.beanFactory
​
​
​
                            .getBeansOfType(EmbeddedServletContainerCustomizer.class,
​
​
​
                                    false, false)
​
​
​
                            .values());
​
​
​
            Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
​
​
​
            this.customizers = Collections.unmodifiableList(this.customizers);
​
​
​
        }
​
​
​
        return this.customizers;
​
​
​
    }
​
​
​
    
​
​
​
    //other code...
​
​
​
}

所以之前介绍可以向容器中添加一个自定义的EmbeddedServletContainerCustomizer类型的组件,用于自定义属性配置,然后在导入的后置处理器中获取到该组件,并调用该自定义组件的customize方法,来修改默认的属性配置。

总结:

? (1)、Spring Boot根据导入容器类型的依赖情况,会给容器中添加相应的EmbeddedServletContainerFactory嵌入式Servlet容器工厂;

(2)、应用程序一旦导入了嵌入式Servlet容器依赖,就会触动后置处理器EmbeddedServletContainerCustomizerBeanPostProcessor

(3)、后置处理器从IOC容器中获取所有的EmbeddedServletContainerCustomizer类型的嵌入式Servlet容器定制器,并调用每个定制器的定制方法customize,从而修改默认属性配置。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐