欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring boot中嵌入式Servlet容器的配置和启动原理

程序员文章站 2022-03-24 12:28:28
以下分析基于Springboot2.0以上版本,1.X版本跟2.0以上版本源码差异性较大嵌入式Servlet容器的自动配置原理流程如下:SpringBoot 根据的依赖信息(默认是tomcat),创建对应的WebServerFactoryCustomizer(定制器,用来定制一些属性,默认为tomcat 所以就是定制tomcat的一些属性);WebServerFactoryCustomizerBeanPostProcessor(web工厂定制器的后置处理器)获取所有类型为web服务工厂定制器的组件(...

以下分析基于Springboot2.0以上版本,1.X版本跟2.0以上版本源码差异性较大

嵌入式Servlet容器的自动配置原理流程如下:
  1. SpringBoot 根据的依赖信息(默认是tomcat),创建对应的WebServerFactoryCustomizer(定制器,用来定制一些属性,默认为tomcat 所以就是定制tomcat的一些属性);
  2. WebServerFactoryCustomizerBeanPostProcessor(web工厂定制器的后置处理器)获取所有类型为web服务工厂定制器的组件(类型为WebServerFactoryCustomizer,以及我们自己自定义的组件),依次调用customize()方法,设置Servlet容器属性;
  3. 嵌入式的Servlet容器工厂创建tomcat容器,初始化并启动容器。
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\ //Springboot在启动的时候会默认加载这个自动配置类
//关于Springboot的自动配置,大家可以关注我的另外一篇博客《Spring boot的自动配置原理解析》
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\


========
代码块1
//我们首先来找到这个默认配置类ServletWebServerFactoryAutoConfiguration

@EnableConfigurationProperties({ServerProperties.class})
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, //这里主要是注册一些后置处理器信息
//(关注的主要是这个webServerFactoryCustomizerBeanPostProcessor后置处理器)
EmbeddedTomcat.class, //注册TomcatServletWebServerFactory,并将其放到容器之中,此处点进去的代码贴在下方代码块2
EmbeddedJetty.class, //注册JettyServletWebServerFactory,并将其放到容器之中
EmbeddedUndertow.class})//注册UndertowServletWebServerFactory 并将其放到容器之中
public class ServletWebServerFactoryAutoConfiguration {
    public ServletWebServerFactoryAutoConfiguration() {
    }
    @Bean
    public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
        return new ServletWebServerFactoryCustomizer(serverProperties);
    }
    @Bean
    @ConditionalOnClass(
        name = {"org.apache.catalina.startup.Tomcat"}
    )
    public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
        return new TomcatServletWebServerFactoryCustomizer(serverProperties);
    }
    @Bean
    @ConditionalOnMissingFilterBean({ForwardedHeaderFilter.class})
    @ConditionalOnProperty(
        value = {"server.forward-headers-strategy"},
        havingValue = "framework"
    )
    public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
        ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
        FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean(filter, new ServletRegistrationBean[0]);
        registration.setDispatcherTypes(DispatcherType.REQUEST, new DispatcherType[]{DispatcherType.ASYNC, DispatcherType.ERROR});
        registration.setOrder(-2147483648);
        return registration;
    }
    public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
        private ConfigurableListableBeanFactory beanFactory;

        public BeanPostProcessorsRegistrar() {
        }
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            if (beanFactory instanceof ConfigurableListableBeanFactory) {
                this.beanFactory = (ConfigurableListableBeanFactory)beanFactory;
            }

        }
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (this.beanFactory != null) {
            //注册webServerFactoryCustomizerBeanPostProcessor后置处理器,
            //这个处理器主要是后来用于获取容器中的WebServerFactoryCustomizer类型组件,并调用其customize()方法。
                this.registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class);
                this.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);
            }

        }
    }
}
==================
代码块2
   static class EmbeddedTomcat {
        EmbeddedTomcat() {
        }
    //将TomcatServletWebServerFactory 放到容器之中
        @Bean
        TomcatServletWebServerFactory tomcatServletWebServerFactory(ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
            factory.getTomcatConnectorCustomizers().addAll((Collection)connectorCustomizers.orderedStream().collect(Collectors.toList()));
            factory.getTomcatContextCustomizers().addAll((Collection)contextCustomizers.orderedStream().collect(Collectors.toList()));
            factory.getTomcatProtocolHandlerCustomizers().addAll((Collection)protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
            return factory;
        }
    }

=================
代码块3
//在把将TomcatServletWebServerFactory和webServerFactoryCustomizerBeanPostProcessor都注册到容器之中后,
//此时后置处理器就会被调用
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
    //调用this.getCustomizers()来获取所有定制器
        ((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
            customizer.customize(webServerFactory);//调用所有定制器的customize方法
        });
    }

    private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
        if (this.customizers == null) {
            this.customizers = new ArrayList(this.getWebServerFactoryCustomizerBeans());//调用getWebServerFactoryCustomizerBeans来获得容器中所有为WebServerFactoryCustomizer的组件
            this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
            this.customizers = Collections.unmodifiableList(this.customizers);
        }

        return this.customizers;
    }

    private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
        return this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
    }

================
代码块4
//在调用getWebServerFactoryCustomizerBeans()时候,我们首先来到EmbeddedWebServerFactoryCustomizerAutoConfiguration这个自动配置类之中
    @ConditionalOnClass({Tomcat.class, UpgradeProtocol.class})
    public static class TomcatWebServerFactoryCustomizerConfiguration {
        public TomcatWebServerFactoryCustomizerConfiguration() {
        }
    //返回一个TomcatWebServerFactoryCustomizer定制器并把它加入到容器之中
        @Bean
        public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
            return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
        }
    }
    
===============
代码块5
//从代码块4中,我们得知容器中已经有TomcatWebServerFactoryCustomizer这个定制器了,所以在代码块3中调用customizer.customize(webServerFactory),就是调用这个定制器的customize方法
//接下来来看看这个定制器的customize方法,可以看到这个方法都是对这个定制器属性的一些设置
public void customize(ConfigurableTomcatWebServerFactory factory) {//这里传入的参数就是我们一开始获得的TomcatServletWebServerFactory
        ServerProperties properties = this.serverProperties;
        Tomcat tomcatProperties = properties.getTomcat();
        PropertyMapper propertyMapper = PropertyMapper.get();
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getBasedir).whenNonNull().to(factory::setBaseDirectory);
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getBackgroundProcessorDelay).whenNonNull().as(Duration::getSeconds).as(Long::intValue).to(factory::setBackgroundProcessorDelay);
        this.customizeRemoteIpValve(factory);
        Threads threadProperties = tomcatProperties.getThreads();
        threadProperties.getClass();
        propertyMapper.from(threadProperties::getMax).when(this::isPositive).to((maxThreads) -> {
            this.customizeMaxThreads(factory, threadProperties.getMax());
        });
        threadProperties.getClass();
        propertyMapper.from(threadProperties::getMinSpare).when(this::isPositive).to((minSpareThreads) -> {
            this.customi*Threads(factory, minSpareThreads);
        });
        propertyMapper.from(this.serverProperties.getMaxHttpHeaderSize()).whenNonNull().asInt(DataSize::toBytes).when(this::isPositive).to((maxHttpHeaderSize) -> {
            this.customizeMaxHttpHeaderSize(factory, maxHttpHeaderSize);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getMaxSwallowSize).whenNonNull().asInt(DataSize::toBytes).to((maxSwallowSize) -> {
            this.customizeMaxSwallowSize(factory, maxSwallowSize);
        });
        tomcatProperties.getClass();
        propertyMapper.from(tomcatProperties::getMaxHttpFormPostSize).asInt(DataSize::toBytes).when((maxHttpFormPostSize) -> {
            return maxHttpFormPostSize != 0;
        }).to((maxHttpFormPostSize) -> {
            this.customizeMaxHttpFormPostSize(factory, maxHttpFormPostSize);
        });
        .......
    }

到这一步嵌入式Servlet容器的配置就结束了

我们再来通过debug来验证下这个流程,下面图片的顺序为debug跑的顺序
Spring boot中嵌入式Servlet容器的配置和启动原理
Spring boot中嵌入式Servlet容器的配置和启动原理
Spring boot中嵌入式Servlet容器的配置和启动原理
Spring boot中嵌入式Servlet容器的配置和启动原理
Spring boot中嵌入式Servlet容器的配置和启动原理
Spring boot中嵌入式Servlet容器的配置和启动原理
Spring boot中嵌入式Servlet容器的配置和启动原理
了解了嵌入式Servlet容器的配置,接下来来看看tomcat是怎么被启动的

//首先我们追寻主方法中的这行代码
SpringApplication.run(DemoApplication.class, args);

//一路点击进去,可以看到这个方法
//SpringApplication.class
    public ConfigurableApplicationContext run(String... args) {
        ...省略部分代码
        try {
            .....
            context = this.createApplicationContext();//创建IOC容器
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            this.refreshContext(context);//刷新IOC容器,重点也在这个方法里面
            //通过debug得到context的值为AnnotationConfigServletWebServerApplicationContext
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }

            listeners.started(context);
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }
        ....
    }
//接下来我们继续追寻这个函数refreshContext的调用
//SpringApplication.class
    private void refreshContext(ConfigurableApplicationContext context) {
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
            }
        }

        this.refresh((ApplicationContext)context);
    }
    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
        this.refresh((ConfigurableApplicationContext)applicationContext);
    }
    protected void refresh(ConfigurableApplicationContext applicationContext) {
        applicationContext.refresh();//applicationContext为AnnotationConfigServletWebServerApplicationContext
    }
  //ServletWebServerApplicationContext.class  
    public final void refresh() throws BeansException, IllegalStateException {
        try {
            super.refresh();
        } catch (RuntimeException var3) {
            WebServer webServer = this.webServer;
            if (webServer != null) {
                webServer.stop();
            }

            throw var3;
        }
    }
    //AbstractApplicationContext.class
        public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();//这里是比较关键的地方ServletWebServerApplicationContext重写了这个方法
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
    //ServletWebServerApplicationContext.class
    protected void onRefresh() {
        super.onRefresh();

        try {
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }
    //ServletWebServerApplicationContext.class
        private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = this.getWebServerFactory();// 还记得上面说过Springboot的自动配置会在容器中加这样一个工厂:TomcatServletWebServerFactory
            //调用了TomcatServletWebServerFactory的getWebServer方法,这个是重点,继续追进去看看
            this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
            this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
            this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
        } else if (servletContext != null) {
            try {
                this.getSelfInitializer().onStartup(servletContext);
            } catch (ServletException var4) {
                throw new ApplicationContextException("Cannot initialize servlet context", var4);
            }
        }

        this.initPropertySources();
    }
    
    //TomcatServletWebServerFactory.class
        public WebServer getWebServer(ServletContextInitializer... initializers) {
        if (this.disableMBeanRegistry) {
            Registry.disableRegistry();
        }
        Tomcat tomcat = new Tomcat();//追到这里总算看到了tomcat对象的创建
        File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        Connector connector = new Connector(this.protocol);
        connector.setThrowOnFailure(true);
        tomcat.getService().addConnector(connector);
        this.customizeConnector(connector);
        tomcat.setConnector(connector);
        tomcat.getHost().setAutoDeploy(false);
        this.configureEngine(tomcat.getEngine());
        Iterator var5 = this.additionalTomcatConnectors.iterator();

        while(var5.hasNext()) {
            Connector additionalConnector = (Connector)var5.next();
            tomcat.getService().addConnector(additionalConnector);
        }

        this.prepareContext(tomcat.getHost(), initializers);
        return this.getTomcatWebServer(tomcat);//返回的这个对象,重点
    
    }
    
    //TomcatWebServer.class
     public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
        this.monitor = new Object();
        this.serviceConnectors = new HashMap();
        Assert.notNull(tomcat, "Tomcat Server must not be null");
        this.tomcat = tomcat;
        this.autoStart = autoStart;
        this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
        this.initialize();//构造函数中调用
    }

    private void initialize() throws WebServerException {
        logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
        synchronized(this.monitor) {
            try {
                this.addInstanceIdToEngineName();
                Context context = this.findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource()) && "start".equals(event.getType())) {
                        this.removeServiceConnectors();
                    }

                });
                this.tomcat.start();//到这一步 tomcat就起来了
                this.rethrowDeferredStartupExceptions();

                try {
                    ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
                } catch (NamingException var5) {
                }

                this.startDaemonAwaitThread();
            } catch (Exception var6) {
                this.stopSilently();
                this.destroySilently();
                throw new WebServerException("Unable to start embedded Tomcat", var6);
            }

        }
    }

以上就是Springboot中tomcat如何运行起来的一个流程。对于其他servelt容器,大家也可以以此类推,原理性差不多。

以上乃个人学习小结,如果错误,望大佬不吝指教

本文地址:https://blog.csdn.net/weixin_42683077/article/details/109990810