溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

嵌入式Servlet容器是什么?如何配置?

發(fā)布時間:2020-05-15 13:52:33 來源:億速云 閱讀:1440 作者:Leah 欄目:編程語言

今天小編給大家分享的是嵌入式Servlet容器的詳細介紹,相信大部分人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,話不多說,一起往下看吧。

1、前言簡單介紹

SpringBoot的自動配置就是SpringBoot的精髓所在;對于SpringBoot項目是不需要配置Tomcat、jetty等等Servlet容器,直接啟動application類既可,SpringBoot為什么能做到這么簡捷?原因就是使用了內(nèi)嵌的Servlet容器,默認是使用Tomcat的,具體原因是什么?為什么啟動application就可以啟動內(nèi)嵌的Tomcat或者其它Servlet容器?ok,本文就已SpringBoot嵌入式Servlet的啟動原理簡單介紹一下

環(huán)境準備:

  • SmartGit
  • IntelliJ IDEA
  • Maven
  • SpringBoot2.2.1

本文先創(chuàng)建一個SpringBoot項目,基于最新的2.2.1版本,閱讀源碼之前先進行一些必要的應用代碼實踐,先學習應用實踐,有助于理解源碼

在SpringBoot官網(wǎng)找到嵌入式Servlet容器相關(guān)的描述:
嵌入式Servlet容器是什么?如何配置?

Under the hood, Spring Boot uses a different type of ApplicationContext for embedded servlet container support. The ServletWebServerApplicationContext is a special type of WebApplicationContext that bootstraps itself by searching for a single ServletWebServerFactory bean. Usually a TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory has been auto-configured.

這是比較重要的信息,簡單翻譯一下,里面提到ServletWebServerApplicationContext這是一種特殊的ApplicationContext 類,也就是啟動時候,用來掃描ServletWebServerFactory類型的類的,ServletWebServerFactory類是一個接口類,具體的實現(xiàn)類是TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory etc.

2、定制servlet容器

然后如何自定義嵌入式Servlet容器的配置?在官方文檔里找到如圖對應的描述:
嵌入式Servlet容器是什么?如何配置?

方法1:修改application配置

從官方文檔可以看出支持的配置有如下所示,所以要修改servlet容器配置,直接在application配置文件修改即可:

  • 網(wǎng)絡(luò)設(shè)置: 監(jiān)聽端口(server.port)、服務器地址(server.address)等等
  • Session設(shè)置: 會話是否持久 (server.servlet.session.persistent),會話超時(server.servlet.session.timeout), 會話數(shù)據(jù)的位置 (server.servlet.session.store-dir), 會話對應的cookie配置 (server.servlet.session.cookie.*) 等等
  • 錯誤管理: 錯誤頁面位置 (server.error.path)等等
  • SSL設(shè)置:具體參考Configure SSL
  • HTTP compression:具體參考Enable HTTP Response Compression

方法2:自定義WebServerFactoryCustomizer定制器類

從文檔里還找到了通過新建自定義的WebServerFactoryCustomizer類來實現(xiàn)屬性配置修改,WebServerFactoryCustomizer也就是一種定制器類:

import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

/**
 * <pre>
 *  自定義的WebServerFactory定制器類
 * </pre>
 * @author nicky
 * <pre>
 * 修改記錄
 *    修改后版本:     修改人:  修改日期: 2019年12月01日  修改內(nèi)容:
 * </pre>
 */
@Component
public class WebServerFactoryCustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    @Override
    public void customize(ConfigurableServletWebServerFactory server) {
        server.setPort(8081);
    }

}

ok,官方文檔里提供了如上的代碼實例,當然也可以通過@bean注解進行設(shè)置,代碼實例如:

@Configuration
public class MyServerConfig {

    /**
     * 自定義的WebServerFactory定制器類
     * @return
     */
    @Bean
    public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerFactoryCustomizer(){
        return new WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>() {
            @Override
            public void customize(ConfigurableServletWebServerFactory factory) {
                factory.setPort(8082);
            }
        };
    }
}

3、變換servlet容器

SpringBoot2.2.1版本支持的內(nèi)嵌servlet容器有tomcat、jetty(適用于長連接)、undertow(高并發(fā)性能不錯,但是默認不支持jsp),不過項目默認使用的是Tomcat的

我們可以找新建的一個SpringBoot項目,要求是集成了spring-boot-starter-web的工程,在pom文件右鍵->Diagrams->Show Dependencies,可以看到對應的jar關(guān)系圖:
嵌入式Servlet容器是什么?如何配置?

ok,從圖可以看出,SpringBoot默認使用是Servlet容器是Tomcat,然后如果要切換其它嵌入式Servlet容器,要怎么實現(xiàn)?我們可以在圖示選擇spring-boot-starter-tomcat右鍵exclusion,然后引入其它的servlet容器,pom配置如圖:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>

4、servlet容器啟動原理

ok,有了前面應用方面的學習之后,就可以簡單跟一下Springboot是怎么對servlet容器進行自動配置的?內(nèi)嵌的默認Tomcat容器是怎么樣啟動的?

從之前博客的學習,可以知道Springboot的自動配置都是通過一些AutoConfiguration類進行自動配置的,所以同理本博客也找一些對應的類,ServletWebServerFactoryAutoConfiguration 就是嵌入式servlet容器的自動配置類,簡單跟一下其源碼

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)//使ServerProperties配置類起效
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
        ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
        ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
        ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })//@Import是Spring框架的注解,作用是將對應組件加載到容器,這里關(guān)鍵的是BeanPostProcessorsRegistrar,一個后置處理類
public class ServletWebServerFactoryAutoConfiguration {

    @Bean
    public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
        return new ServletWebServerFactoryCustomizer(serverProperties);
    }

//Tomcat的定制器類,起作用的條件是有Tomcat對應jar有引入項目的情況,默認是引入的,所以會執(zhí)行Tomcat的servletWeb工廠定制類
    @Bean
    @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
    public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
            ServerProperties serverProperties) {
        return new TomcatServletWebServerFactoryCustomizer(serverProperties);
    }

    ....

    //注冊重要的后置處理器類WebServerFactoryCustomizerBeanPostProcessor,在ioc容器啟動的時候會調(diào)用后置處理器
    public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

        private ConfigurableListableBeanFactory beanFactory;

        //設(shè)置ConfigurableListableBeanFactory
        @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);
            }
        }

    }

}

從自動配置類里,我們并不能很明確地理解自動配置是怎么運行的,只看重關(guān)鍵的一些信息點,比如注冊了Tomcat的ServletWebServer工廠的定制器類,方法是tomcatServletWebServerFactoryCustomizer,還有一個后置處理類BeanPostProcessorsRegistrar,后置處理是Spring源碼里是很關(guān)鍵的,所以這里可以繼續(xù)點一下TomcatServletWebServerFactoryCustomizer,Tomcat的webServer工廠定制器類

也是一個WebServerFactoryCustomizer類型的類,從前面的應用學習,這個類是進行servlet容器的一些定制
嵌入式Servlet容器是什么?如何配置?

這個是關(guān)鍵的方法,主要是拿ServerProperties配置類里的信息進行特定屬性定制
嵌入式Servlet容器是什么?如何配置?

所以,這里就可以知道Tomcat的配置是通過定制器類TomcatServletWebServerFactoryCustomizer進行定制的,其工廠類是TomcatServletWebServerFactory

TomcatServletWebServerFactory工廠類進行Tomcat對象的創(chuàng)建,必要參數(shù)的自動配置
嵌入式Servlet容器是什么?如何配置?

ok,簡單跟了一下源碼之后,我們知道了TomcatServletWebServerFactoryCustomizer是Tomcat的定制器類,Tomcat對象的創(chuàng)建是通過TomcatServletWebServerFactory類的,然后,有個疑問,這個定制器類是什么時候創(chuàng)建的?為什么一啟動Application類,嵌入式的Tomcat也啟動了?打成jar格式的Springboot項目,只要運行jar命令,不需要啟動任何servlet容器,項目也是正常運行的?然后這個BeanPostProcessorsRegistrar后置處理類有什么作用?ok,帶著這些疑問,我們還是用調(diào)試一下源碼

如圖,打斷點調(diào)試,看看Tomcat定制器是怎么創(chuàng)建的?
嵌入式Servlet容器是什么?如何配置?

定制器類被調(diào)用了,其對應的工廠類也會起作用,打個斷點,看看工廠類是怎么調(diào)用的?
嵌入式Servlet容器是什么?如何配置?

ok,啟動Application類,在idea里調(diào)試,如圖,可以跟著調(diào)用順序,一點點跟源碼,如圖所示,調(diào)用了Springboot的run方法
嵌入式Servlet容器是什么?如何配置?

run方法里的刷新上下文方法,refreshContext其實也就是創(chuàng)建ioc容器,初始化ioc容器,并創(chuàng)建容器的每一個組件
嵌入式Servlet容器是什么?如何配置?

這里注意到了,調(diào)用到了ServletWebServerApplicationContext類的refresh方法,ServletWebServerApplicationContext類前面也介紹到了,這個類是一種特殊的ApplicationContext類,也就是一些ioc的上下文類,作用于WebServer類型的類
嵌入式Servlet容器是什么?如何配置?

創(chuàng)建webServer類,先創(chuàng)建ioc容器,調(diào)用基類的onRefresh方法,然后再調(diào)用createWebServer方法
嵌入式Servlet容器是什么?如何配置?

ioc的servletContext組件沒被創(chuàng)建的情況,調(diào)用ServletWebServerFactory類獲取WebServer類,有servletContext的情況,直接從ioc容器獲取
嵌入式Servlet容器是什么?如何配置?

掃描ioc容器里是否有對應的ServletWebServerFactory類,TomcatServletWebServerFactory是其中一種,通過調(diào)試,是有掃描到的,所以從ioc容器里將這個bean對應的信息封裝到ServletWebServerFactory對象
嵌入式Servlet容器是什么?如何配置?

接著是ioc容器創(chuàng)建bean的過程,這個一個比較復雜的過程,因為是單例的,所以是調(diào)用singleObjects進行存儲
嵌入式Servlet容器是什么?如何配置?

bean被創(chuàng)建之后,調(diào)用了后置處理器,這個其實就是Spring的源碼里的bean的創(chuàng)建過程,后置處理器是很關(guān)鍵的,在bean被創(chuàng)建,還沒進行屬性賦值時候,就調(diào)用了后置處理器
嵌入式Servlet容器是什么?如何配置?

關(guān)鍵點,這里是檢測是否有WebServerFactory工廠類,前面的調(diào)試發(fā)現(xiàn)已經(jīng)有Tomcat的WebServer工廠類,所以是會調(diào)用后置處理器的
嵌入式Servlet容器是什么?如何配置?

調(diào)用了WebServerFactoryCustomizerBeanPostProcessor這個后置處理類,然后拿到一個WebServerFactoryCustomizer定制器類,也就是TomcatWebServerFactoryCustomizer,通過后置處理器調(diào)用定制方法customize
嵌入式Servlet容器是什么?如何配置?

然后WebServerFactoryCustomizerBeanPostProcessor這個后置處理器是什么注冊的?往前翻Springboot的自動配置類,在這里找到了WebServerFactoryCustomizerBeanPostProcessor的注冊
嵌入式Servlet容器是什么?如何配置?

ok,繼續(xù)調(diào)試源碼,BeanWrapperImpl創(chuàng)建bean實例
嵌入式Servlet容器是什么?如何配置?

ok,Tomcat定制器類被調(diào)用了,是通過后置處理器調(diào)用的
嵌入式Servlet容器是什么?如何配置?

然后就是之前跟過的定制方法customize執(zhí)行:
嵌入式Servlet容器是什么?如何配置?

Tomcat的WebServer工廠類創(chuàng)建Tomcat對象實例,進行屬性配置,引擎設(shè)置等等
嵌入式Servlet容器是什么?如何配置?

端口有設(shè)置就創(chuàng)建TomcatwebServer對象
嵌入式Servlet容器是什么?如何配置?

TomcatWebServer啟動Tomcat,如圖代碼所示:
嵌入式Servlet容器是什么?如何配置?

ok,跟了源碼,您是否有一個疑問?Tomcat的工廠類TomcatServletWebServerFactory是什么時候創(chuàng)建的?好的,返回前面配置類看看,如圖,這里用import引入了EmbeddedTomcat類
嵌入式Servlet容器是什么?如何配置?

ok,EmbeddedTomcat是一個內(nèi)部的配置類,條件是有引入Tomcat對應的jar,就會自動創(chuàng)建工廠類,很顯然,Springboot默認是有引入的
嵌入式Servlet容器是什么?如何配置?

ok,經(jīng)過源碼比較簡單的學習,思路就很清晰了

Springboot的ServletWebServerFactoryAutoConfiguration是嵌入式Servlet容器的自動配置類,這個類的主要作用是創(chuàng)建TomcatServletWebServerFactory工廠類,創(chuàng)建定制器類TomcatServletWebServerFactoryCustomizer,創(chuàng)建FilterRegistrationBean類,同時很關(guān)鍵的一步是注冊后置處理器webServerFactoryCustomizerBeanPostProcessor

然后Springboot的Application類一啟動,就會執(zhí)行run方法,run經(jīng)過一系列調(diào)用會通過ServletWebServerApplicationContext的onRefresh方法創(chuàng)建ioc容器,然后通過createWebServer方法,createWebServer方法會去ioc容器里掃描是否有對應的ServletWebServerFactory工廠類(TomcatServletWebServerFactory是其中一種),掃描得到,就會觸發(fā)webServerFactoryCustomizerBeanPostProcessor后置處理器類,這個處理器類會獲取TomcatServletWebServerFactoryCustomizer定制器,并調(diào)用customize方法進行定制,這時候工廠類起作用,調(diào)用getWebServer方法進行Tomcat屬性配置和引擎設(shè)置等等,再創(chuàng)建TomcatWebServer啟動Tomcat容器

關(guān)于嵌入式Servlet容器就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果喜歡這篇文章,不如把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI