[Tomcat]瞭解Tomcat,從它的結構開始

Tomcat8 的主要目錄結構

  • bin 存放可執行文件
  • conf 存放配置文件
  • lib 存放Tomcat運行需要的包
  • logs 存放運行的日誌
  • webapps 存放默認的web應用部署目錄
  • work 存放web應用代碼生成和編譯文件的臨時目錄

組件結構

  • connector,負責接收和反饋外部請求的連接器
  • container,負責處理請求的容器
  • service,由connecter和container一起構成,Tomcat可以管理多個service,每個service之間相互獨立

連接器

  • 核心功能

1,監聽網絡端口,接收和相應網絡請求。

2,網絡字節流處理,將收到的網絡字節流轉換成TomcatRequest再轉成標準的ServletRequest給容器。

同時將容器傳回來的ServletResponse轉爲TomcatResponse再轉成網絡字節流。

  • 模塊設計

1,EndPointer,端點,用來處理Socket接收和發送的邏輯,內部由Acceptor監聽請求,Handler處理數據,AsyncTimeout檢查請求超時,具體實現有NioEndPoint,AprEndPointer。

2,Processor,處理器,負責構建TomcatRequest和TomcatResponse對象,具體的實現是Http11Processor,StreamProcessor等等。

3,Adapter,適配器,實現TomcatRequest和ServletRequest的互相轉換,採用了經典的適配器模式。

4,ProtocolHandler,協議處理器,將不同協議和通訊方式組合封裝成對應的協議處理器。

avatar

容器

  • 容器結構

每個Service會包含一個容器,容易有一個引擎,可以管理多個虛擬主機,每個虛擬主機可以管理多個web應用,每個web應用會有多個Servlet包裝器,

1,Engine,引擎,可以管理多個虛擬主機

2,Host,虛擬主機,負責多個應用的部署

3,Context,web應用,包含多個Servlet封裝器

4,Wrapper,封裝器,容器的最底層,對Servlet進行封裝,負責實例的創建,執行和銷燬。

這四個按順序爲父子關係。

容器請求處理

容器的請求處理過程就是上面所提到的四個容器之間的層層調用,最後在Servlet中執行相應的業務邏輯,各個容器都會有一個通道pipeline,每個通道上都會有一個BasicValue,類似於一個閘門,用來處理Request和Response。

avatar

映射器

映射器,將請求url的地址匹配由哪個容器來處理,其中每個容器都有自己實現自己的映射器。

淺析Tomcat處理一個http請求的流程

以http://localhost:8080/docs/api爲例

1,連接器監聽的端口是8080,連接器接收該請求。

2,引擎的默認虛擬主機是localhost,並且虛擬主機的目錄是webapps,所以請求找到tomcat/webapps目錄

3,解析docs是web程序的應用名,也就是context上下文,此時請求繼續從webapps目錄下找到docs目錄。

4,解析的api是具體的業務邏輯地址,此時需要從docs/WEB-INF/web.xml中找到映射關係,最後調用具體的函數。

avatar

Springboot啓動內嵌Tomcat的過程

說實話,一直在用Springboot,確實還沒了解過內嵌Tomcat的使用方法。中小型項目雖然可以直接內嵌Tomcat啓動,但是遇到大型項目,需要用到Tomcat集羣,並且需要調優,那可能就不能滿足了。

從SpringBoot main函數開始看

SpringAppliation.run();

avatar

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        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();
                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();
            }

        }
    }

繼續往裏面看就是上面這個refresh方法,然後在看到這裏的onRefresh方法,熟悉的肯定這個名字就是典型的模板方法,那繼續看下去。在ServletWebServerApplicationContxt再看onRefresh()

    protected void onRefresh() {
        super.onRefresh();

        try {
            this.createWebServer();
        } catch (Throwable var2) {
            throw new ApplicationContextException("Unable to start web server", var2);
        }
    }

這裏就會創建WebServer了,再看這裏頭做了什麼。

    private void createWebServer() {
        WebServer webServer = this.webServer;
        ServletContext servletContext = this.getServletContext();
        if (webServer == null && servletContext == null) {
            ServletWebServerFactory factory = this.getWebServerFactory();
            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();
    }

看到getWebServerFactory,去找對應的實現方法。在TomcatServletWebServerFactory裏找到對應的方法。

    public WebServer getWebServer(ServletContextInitializer... initializers) {
        if (this.disableMBeanRegistry) {
            Registry.disableRegistry();
        }

        Tomcat tomcat = new 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);
    }

這裏終於可以看到和之前整理的Tomcat結構相關的東西了,在這裏配置了基本的連接器,引擎和虛擬站點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章