最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?boot整合tomcat底層原理剖析

 更新時間:2022年10月14日 08:33:54   作者:zfcq  
SpringBoot的啟動過程中,會調(diào)用核心的refresh方法,內(nèi)部會執(zhí)行onRefresh()方法,onRefresh()方法是一個模板方法,他會執(zhí)行會執(zhí)行子類ServletWebServerApplicationContext的onRefresh()方法,這篇文章主要介紹了Spring?boot整合tomcat底層原理,需要的朋友可以參考下

從源碼層面理解spring boot的默認web容器,以及他們是如何關聯(lián)起來的。

本文結論

  • 源碼基于spring boot2.6.6
  • 項目的pom.xml中存在spring-boot-starter-web的時候,在項目啟動時候就會自動啟動一個Tomcat。
  • 自動配置類ServletWebServerFactoryAutoConfiguration找到系統(tǒng)中的所有web容器。我們以tomcat為主。
  • 構建TomcatServletWebServerFactory的bean。
  • SpringBoot的啟動過程中,會調(diào)用核心的refresh方法,內(nèi)部會執(zhí)行onRefresh()方法,onRefresh()方法是一個模板方法,他會執(zhí)行會執(zhí)行子類ServletWebServerApplicationContext的onRefresh()方法。
  • onRefresh()方法中調(diào)用getWebServer啟動web容器。

spring-boot-starter-web內(nèi)部有什么?

  • 在spring-boot-starter-web這個starter中,其實內(nèi)部間接的引入了spring-boot-starter-tomcat這個starter,這個spring-boot-starter-tomcat又引入了tomcat-embed-core依賴,所以只要我們項目中依賴了spring-boot-starter-web就相當于依賴了Tomcat。

自動配置類:ServletWebServerFactoryAutoConfiguration在spring-boot-autoconfigure-2.6.6.jar這個包中的spring.factories文件內(nèi),配置了大量的自動配置類,其中就包括自動配置tomcat的自動配置類:ServletWebServerFactoryAutoConfiguration

自動配置類的代碼如下

// full模式
@Configuration(proxyBeanMethods = false)

// 配置類解析順序
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)

// 條件注解:表示項目依賴中要有ServletRequest類(server api)
@ConditionalOnClass(ServletRequest.class)
// 表示項目應用類型得是SpringMVC(在啟動過程中獲取的SpringBoot應用類型)
@ConditionalOnWebApplication(type = Type.SERVLET)

// 讀取server下的配置文件
@EnableConfigurationProperties(ServerProperties.class)

// import具體的加載配置的類和具體web實現(xiàn)容器
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
	......
}
  • ServletRequest是存在于tomcat-embed-core-9.0.60.jar中的的一個類,所以@ConditionalOnClass(ServletRequest.clas s)會滿足。
  • spring-boot-starter-web中,間接的引入了spring-web、spring-webmvc等依賴,所以@ConditionalOnWebApplication(type = Type.SERVLET)條件滿足。
  • 上面的倆個條件都滿足,所以spring回去解析這個配置類,在解析過程中會發(fā)現(xiàn)他import了三個類!我們重點關注EmbeddedTomcat。其他倆個的內(nèi)部條件注解不滿足!
@Configuration(proxyBeanMethods = false)
// tomcat內(nèi)部的類,肯定都存在
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })

// 程序員如果自定義了ServletWebServerFactory的Bean,那么這個Bean就不加載。
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
    @Bean
    TomcatServletWebServerFactory tomcatServletWebServerFactory(
        ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
        ObjectProvider<TomcatContextCustomizer> contextCustomizers,
        ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
            TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
            // orderedStream()調(diào)用時會去Spring容器中找到TomcatConnectorCustomizer類型的Bean,默認是沒有的,程序員可以自己定義。這個Bean可以設置一些tomcat的配置,比如端口、協(xié)議...
            // TomcatConnectorCustomizer:是用來配置Tomcat中的Connector組件的
            factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
            // TomcatContextCustomizer:是用來配置Tomcat中的Context組件的
            factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
            // TomcatProtocolHandlerCustomizer:是用來配置Tomcat中的ProtocolHandler組件的
            factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
            return factory;
        }
    }
}
  • 對于另外的EmbeddedJetty和EmbeddedUndertow,邏輯類似,都是判斷項目依賴中是否有Jetty和Undertow的依賴,如果有,那么對應在Spring容器中就會存在JettyServletWebServerFactory類型的Bean、或者存在UndertowServletWebServerFactory類型的Bean。

TomcatServletWebServerFactory的作用:獲取WebServer對象

  • TomcatServletWebServerFactory他實現(xiàn)了ServletWebServerFactory這個接口。
  • ServletWebServerFactory接口內(nèi)部只有一個方法是獲取WebServer對象。

  • WebServer擁有啟動、停止、獲取端口等方法,就會發(fā)現(xiàn)WebServer其實指的就是Tomcat、Jetty、Undertow。

  • 而TomcatServletWebServerFactory就是用來生成Tomcat所對應的WebServer對象,具體一點就是TomcatWebServer對象,并且在生成TomcatWebServer對象時會把Tomcat給啟動起來。
  • 在源碼中,調(diào)用TomcatServletWebServerFactory對象的getWebServer()方法時就會啟動Tomcat。
public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
        Registry.disableRegistry();
    }
    // 構建tomcat對象
    Tomcat tomcat = new Tomcat();

    // 設置相關的屬性
    File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    for (LifecycleListener listener : this.serverLifecycleListeners) {
        tomcat.getServer().addLifecycleListener(listener);
    }
    Connector connector = new Connector(this.protocol);
    connector.setThrowOnFailure(true);
    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,這個方法內(nèi)部有this.tomcat.start();
    return getTomcatWebServer(tomcat);
}

spring boot啟動的時候啟動tomcat

  • SpringBoot的啟動過程中,會調(diào)用核心的refresh方法,內(nèi)部會執(zhí)行onRefresh()方法,onRefresh()方法是一個模板方法,他會執(zhí)行會執(zhí)行子類ServletWebServerApplicationContext的onRefresh()方法。
protected void onRefresh() {
    // 模板方法,先調(diào)用它父類的,一般是空方法
    super.onRefresh();
    try {
        // 創(chuàng)建web容器
        createWebServer();
    }
    catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

這個方法會調(diào)用createWebServer()方法。

// 最核心的倆行代碼
private void createWebServer() {
    ......
    // 獲取web容器,多個或者沒有的時候報錯
    ServletWebServerFactory factory = getWebServerFactory();

    // 調(diào)用這個容器的getWebServer方法,上面的啟動tomcat的方法!
    this.webServer = factory.getWebServer(getSelfInitializer());
    ......
}
  • getWebServerFactory控制項目組有且只能有一個web容器!
protected ServletWebServerFactory getWebServerFactory() {
    // Use bean names so that we don't consider the hierarchy

    // 得到所有類型為ServletWebServerFactory的Bean。TomcatServletWebServerFactory、JettyServletWebServerFactory、UndertowServletWebServerFactory都是他得到子類!
    String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);

    // 不存在,報錯
    if (beanNames.length == 0) {
        throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
    }

    // 存在不止一個,報錯!
    if (beanNames.length > 1) {
        throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
    }

    // 返回唯一的一個web容器!
    return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}

獲取tomcat的配置

  • 自動配置類ServletWebServerFactoryAutoConfiguration上除了import三個web容器,還import了BeanPostProcessorsRegistrar。
  • BeanPostProcessorsRegistrar實現(xiàn)了ImportBeanDefinitionRegistrar,所以他會在spring啟動的時候調(diào)用registerBeanDefinitions方法。
  • registerBeanDefinitions會注冊一個Bean:webServerFactoryCustomizerBeanPostProcessor。
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // Bean工廠,一個Aware回調(diào)進行賦值
    if (this.beanFactory == null) {
        return;
    }
    // 注冊webServerFactoryCustomizerBeanPostProcessor這個Bean。
    registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
        WebServerFactoryCustomizerBeanPostProcessor.class,
        WebServerFactoryCustomizerBeanPostProcessor::new);

    // 注冊errorPageRegistrarBeanPostProcessor
    registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
        ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
}
  • webServerFactoryCustomizerBeanPostProcessor實現(xiàn)了BeanPostProcessor,所以他會在啟動的時候調(diào)用postProcessBeforeInitialization方法。
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
    // 找到WebServerFactoryCustomizer的Bean
    LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
        // 標記日志用的類
        .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
        // 調(diào)用customize方法,傳入webServerFactory
        .invoke((customizer) -> customizer.customize(webServerFactory));
}
  • postProcessBeforeInitialization中會調(diào)用WebServerFactoryCustomizer類customize方法,在系統(tǒng)中的唯一實現(xiàn):ServletWebServerFactoryCustomizer的customize方法。
  • customize把配置中的內(nèi)容設置到ConfigurableServletWebServerFactory對象中。他的實現(xiàn)TomcatServletWebServerFactory在啟動的時候就會有值!
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
    PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
    map.from(this.serverProperties::getPort).to(factory::setPort);
    map.from(this.serverProperties::getAddress).to(factory::setAddress);
    map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
    map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
    map.from(this.serverProperties.getServlet()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);
    map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
    map.from(this.serverProperties::getSsl).to(factory::setSsl);
    map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
    map.from(this.serverProperties::getCompression).to(factory::setCompression);
    map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
    map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
    map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
    map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
    for (WebListenerRegistrar registrar : this.webListenerRegistrars) {
        registrar.register(factory);
    }
    if (!CollectionUtils.isEmpty(this.cookieSameSiteSuppliers)) {
        factory.setCookieSameSiteSuppliers(this.cookieSameSiteSuppliers);
    }
}

ServletWebServerFactoryCustomizer這個Bean是哪里的?

  • 在我們自動配置類ServletWebServerFactoryAutoConfiguration中定義。
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties, ObjectProvider<WebListenerRegistrar> webListenerRegistrars, ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers) {
    return new ServletWebServerFactoryCustomizer(serverProperties,webListenerRegistrars.orderedStream().collect(Collectors.toList()),cookieSameSiteSuppliers.orderedStream().collect(Collectors.toList()));
}

到此這篇關于Spring boot整合tomcat底層原理的文章就介紹到這了,更多相關Spring boot整合tomcat內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • tomcat漏洞匯總

    tomcat漏洞匯總

    本文主要介紹了tomcat漏洞匯總,文中通過代碼和示例介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-05-05
  • tomcat雙擊startup.bat一閃而過(閃退)的問題解決

    tomcat雙擊startup.bat一閃而過(閃退)的問題解決

    本文主要介紹了tomcat雙擊startup.bat一閃而過(閃退)的問題解決,可能是tomcat找不到你的jdk環(huán)境配置路徑,下面就來介紹一下解決方法,感興趣的可以了解一下
    2024-05-05
  • Tomcat 檢測內(nèi)存泄漏實例詳解

    Tomcat 檢測內(nèi)存泄漏實例詳解

    這篇文章主要介紹了 Tomcat 檢測內(nèi)存泄漏實例詳解的相關資料,需要的朋友可以參考下
    2016-12-12
  • Tomcat用戶管理的優(yōu)化配置詳解

    Tomcat用戶管理的優(yōu)化配置詳解

    這篇文章主要為大家介紹了Tomcat用戶管理的優(yōu)化配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-03-03
  • 使用IDEA配置tomcat及創(chuàng)建JSP文件的方法

    使用IDEA配置tomcat及創(chuàng)建JSP文件的方法

    這篇文章主要介紹了使用IDEA配置tomcat及創(chuàng)建JSP文件的方法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • 學習javaweb如何配置Tomcat的熱啟動

    學習javaweb如何配置Tomcat的熱啟動

    學習javaweb的時候每次更改項目都需要重新部署項目,如此一來比較麻煩,使用tomcat的熱啟動就可以解決這個問題
    2014-09-09
  • startup.bat啟動Tomcat閃退問題原因及解決

    startup.bat啟動Tomcat閃退問題原因及解決

    本文主要介紹了startup.bat啟動Tomcat閃退問題原因及解決,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 解析Tomcat的啟動腳本--startup.bat

    解析Tomcat的啟動腳本--startup.bat

    本文主要對Tomcat的三個最重要的啟動腳本之一--startup.bat腳本做了詳細分析,具有很好的參考價值,需要的朋友可以看下
    2016-12-12
  • IDEA中Smart?Tomcat插件使用教程

    IDEA中Smart?Tomcat插件使用教程

    本文主要介紹了IDEA中Smart?Tomcat插件使用教程,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-06-06
  • 關于tomcat下啟動solr遇到的問題及解決

    關于tomcat下啟動solr遇到的問題及解決

    這篇文章主要介紹了關于tomcat下啟動solr遇到的問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07

最新評論

阜宁县| 延寿县| 胶南市| 南华县| 民勤县| 武邑县| 南华县| 马山县| 重庆市| 广饶县| 卓资县| 石棉县| 濉溪县| 大石桥市| 韶关市| 疏附县| 永昌县| 南丰县| 磐安县| 开鲁县| 齐齐哈尔市| 花垣县| 鸡泽县| 营口市| 深州市| 三门县| 德化县| 南丹县| 南丹县| 瓦房店市| 滕州市| 宝清县| 安吉县| 霞浦县| 德化县| 洞头县| 宜宾县| 临朐县| 富锦市| 白朗县| 涿鹿县|