Tomcat之源碼整體架構設計介紹

1.源碼引入

1.1.1.server.xml:截圖樣例(整體的組件配置文件)

在這裏插入圖片描述

1.1.2.附帶源文件:server.xml

<?xml version='1.0' encoding='utf-8'?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!-- Note:  A "Server" is not itself a "Container", so you may not
     define subcomponents such as "Valves" at this level.
     Documentation at /docs/config/server.html
 -->
<Server port="8005" shutdown="SHUTDOWN">
  <!-- Security listener. Documentation at /docs/config/listeners.html
  <Listener className="org.apache.catalina.security.SecurityListener" />
  -->
  <!--APR library loader. Documentation at /docs/apr.html -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <!-- Global JNDI resources
       Documentation at /docs/jndi-resources-howto.html
  -->
  <GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <!-- A "Service" is a collection of one or more "Connectors" that share
       a single "Container" Note:  A "Service" is not itself a "Container",
       so you may not define subcomponents such as "Valves" at this level.
       Documentation at /docs/config/service.html
   -->
  <Service name="Catalina">

    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
    <!--
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="150" minSpareThreads="4"/>
    -->


    <!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL HTTP/1.1 Connector on port 8080
    -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- A "Connector" using the shared thread pool-->
    <!--
    <Connector executor="tomcatThreadPool"
               port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    -->
    <!-- Define a SSL HTTP/1.1 Connector on port 8443
         This connector uses the NIO implementation that requires the JSSE
         style configuration. When using the APR/native implementation, the
         OpenSSL style configuration is required as described in the APR/native
         documentation -->
    <!--
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" />
    -->

    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />


    <!-- An Engine represents the entry point (within Catalina) that processes
         every request.  The Engine implementation for Tomcat stand alone
         analyzes the HTTP headers included with the request, and passes them
         on to the appropriate Host (virtual host).
         Documentation at /docs/config/engine.html -->

    <!-- You should set jvmRoute to support load-balancing via AJP ie :
    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
    -->
    <Engine name="Catalina" defaultHost="localhost">

      <!--For clustering, please take a look at documentation at:
          /docs/cluster-howto.html  (simple how to)
          /docs/config/cluster.html (reference documentation) -->
      <!--
      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
      -->

      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
           via a brute-force attack -->
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
    </Engine>
  </Service>
</Server>

1.1.3.層次結構圖

在這裏插入圖片描述

2.整體架構圖

2.1.通過上面的結構層級,得出下面的整體架構圖架構圖

在這裏插入圖片描述

2.2.整體架構圖流程說明

首先我們需要理解的問題是:
1.圖示中的每一個組件對應着源碼中那個類圖?
2.tomcat如何接收的?誰接收的?---->Connector
3.tomcat在處理的過程中如何進入到具體的servlet業務邏輯中進行處理? 

3.Tomcat架構中各個組件的含義

https://tomcat.apache.org/tomcat-8.0-doc/architecture/overview.html

3.1.Server

3.1.1.類圖示

在這裏插入圖片描述

3.1.2.概念

1.In the Tomcat world, a Server represents the whole container. Tomcat provides a default implementation of the 
  Server interface which is rarely customized by users.
  Server代表整個容器,Tomcat提供給了一個Server接口的默認實現,用戶很少去自定義;
2.Server 可以認爲是一個頂級的容器,啓動了Server容器,其他的組件也就可以使用;  

3.2.Service

3.2.1.類圖示

在這裏插入圖片描述

3.2.2.概念

A Service is an intermediate component which lives inside a Server and ties one or more Connectors to exactly one Engine. 
The Service element is rarely customized by users, as the default implementation is simple and sufficient: Service interface.
Service是一個運行在Server內部的一箇中間組件,Service將一個或者多個Connector緊密的連接到Engine組件上面;
Service組件用戶很少去自定義,默認的Service組件Service接口簡單高效的;

3.2.Engine

3.3.1.類圖示

在這裏插入圖片描述

3.3.2.概念

An Engine represents request processing pipeline for a specific Service. 
Engine代表特定服務的請求處理管道。
As a Service may have multiple Connectors, the Engine receives and processes all requests from these connectors,
 handing the response back to the appropriate connector for transmission to the client. 
由於服務可能具有多個Connectors,因此Engine會接收並處理來自這些Connectors的所有請求,
  將響應傳遞迴適當的Connectors以傳輸到客戶端。 
The Engine interface may be implemented to supply custom Engines, though this is uncommon.
儘快Engine自定義接口不太常見,當時Engine接口可以自定義的Engine接口實現,

3.4.Host

3.4.1.類圖示

在這裏插入圖片描述

3.4.2.概念

A Host is an association of a network name, e.g. www.yourcompany.com, to the Tomcat server. 
Host是一個關聯我們服務的網絡的名字,比如www.yourcompany.com
An Engine may contain multiple hosts, and the Host element also supports network aliases 
such as yourcompany.com and abc.yourcompany.com. 
一個Engine可能包含多個Hosts,並且每個host可以配置不同的網絡別名。比如as yourcompany.com 和 abc.yourcompany.com
Users rarely create custom Hosts because the StandardHost implementation provides significant additional functionality.
由於StandardHost接口實現非常的高效,用戶很少創建自定義的hosts;

像我們平時啓動了本地的tomcat服務之後,我們可以直接使用localhost這個host去訪問,我們也可以配置其他的
在這裏插入圖片描述

3.5.Connector

3.5.1.類圖示

在這裏插入圖片描述

3.5.2.概念

https://tomcat.apache.org/tomcat-8.0-doc/architecture/overview.html

1.A Connector handles communications with the client. 
  Connector負責與客戶端的交互;
  There are multiple connectors available with Tomcat.
  Tomcat中有多個是可以使用connectors;
  These include the HTTP connector which is used for most HTTP traffic, especially when running Tomcat as 
  a standalone server, and the AJP connector which implements the AJP protocol used when connecting Tomcat to 
  a web server such as Apache HTTPD server. Creating a customized connector is a significant effort.
  這些Connectors包含Http類型的connector(比如:獨立運行的tomcat服務)
  另外,AJP類型的Connector實現了AJP協議,(比如:tomcat連接Apache Httpd Server類型的web服務)
  創建定製的連接器是一項巨大的工作

在這裏插入圖片描述

3.5.2.源碼流程

源碼追溯,我們可以看到最終是ServerSocket進行監聽
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

3.5.4.EndPoint

1.AbstractEndPoint:對於傳輸層協議的抽象,裏面是寫Socket代碼的
2.JioEndPoint:同步阻塞IO,針對併發量比較大的時候,效率比較低,一個連接要一個線程
3.NIO:同步非阻塞IO,併發量比較大的時候,比較佔優勢,單獨一個線程,處理併發
4.Apr:與本地方法庫進行交互,  

在這裏插入圖片描述

3.5.5.關於協議類型的設置

在這裏插入圖片描述
tomcat8 默認是NIO模式
在這裏插入圖片描述

3.6.Context

3.6.1.類視圖

在這裏插入圖片描述

3.6.2.概念

A Context represents a web application. A Host may contain multiple contexts, each with a unique path. 
Context代表一個web應用。一個Host可能包含多個Context,每一個Context有一個唯一的path地址
The Context interface may be implemented to create custom Contexts, but this is rarely the case 
because the StandardContext provides significant additional functionality.
Conext很少被自定義實現,因爲默認的StandardContext接口提供了高效的功能;

3.5.3.源碼流程

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

3.6.4.Context的配置類ContextConfig:代表加載web.xml中的Servlet類

在這裏插入圖片描述

在這裏插入圖片描述

3.6.4.1.ContextConfig.webConfig()方法介紹

 /**
     * Scan the web.xml files that apply to the web application and merge them
     * using the rules defined in the spec. For the global web.xml files,
     * where there is duplicate configuration, the most specific level wins. ie
     * an application's web.xml takes precedence over the host level or global
     * web.xml file.
     * 掃描web.xml文件,將相關屬性賦予到web應用中使其生效
     */
    protected void webConfig() {
        /*
         * Anything and everything can override the global and host defaults.
         * This is implemented in two parts
         * - Handle as a web fragment that gets added after everything else so
         *   everything else takes priority
         * - Mark Servlets as overridable so SCI configuration can replace
         *   configuration from the defaults
         */

        /*
         * The rules for annotation scanning are not as clear-cut as one might
         * think. Tomcat implements the following process:
         * - As per SRV.1.6.2, Tomcat will scan for annotations regardless of
         *   which Servlet spec version is declared in web.xml. The EG has
         *   confirmed this is the expected behaviour.
         * - As per http://java.net/jira/browse/SERVLET_SPEC-36, if the main
         *   web.xml is marked as metadata-complete, JARs are still processed
         *   for SCIs.
         * - If metadata-complete=true and an absolute ordering is specified,
         *   JARs excluded from the ordering are also excluded from the SCI
         *   processing.
         * - If an SCI has a @HandlesType annotation then all classes (except
         *   those in JARs excluded from an absolute ordering) need to be
         *   scanned to check if they match.
         */
        Set<WebXml> defaults = new HashSet<>();
        defaults.add(getDefaultWebXmlFragment());

        WebXml webXml = createWebXml();

        // Parse context level web.xml
        InputSource contextWebXml = getContextWebXmlSource();
        if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
            ok = false;
        }

        ServletContext sContext = context.getServletContext();

        // Ordering is important here

        // Step 1. Identify all the JARs packaged with the application and those
        // provided by the container. If any of the application JARs have a
        // web-fragment.xml it will be parsed at this point. web-fragment.xml
        // files are ignored for container provided JARs.
        Map<String,WebXml> fragments = processJarsForWebFragments(webXml);

        // Step 2. Order the fragments.
        Set<WebXml> orderedFragments = null;
        orderedFragments =
                WebXml.orderWebFragments(webXml, fragments, sContext);

        // Step 3. Look for ServletContainerInitializer implementations
        if (ok) {
            processServletContainerInitializers(sContext);
        }

        if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
            // Step 4. Process /WEB-INF/classes for annotations and
            // @HandlesTypes matches
            if (ok) {
                WebResource[] webResources =
                        context.getResources().listResources("/WEB-INF/classes");

                for (WebResource webResource : webResources) {
                    processAnnotationsWebResource(webResource, webXml,
                            webXml.isMetadataComplete());
                }
            }

            // Step 5. Process JARs for annotations for annotations and
            // @HandlesTypes matches - only need to process those fragments we
            // are going to use (remember orderedFragments includes any
            // container fragments)
            if (ok) {
                processAnnotations(
                        orderedFragments, webXml.isMetadataComplete());
            }

            // Cache, if used, is no longer required so clear it
            javaClassCache.clear();
        }

        if (!webXml.isMetadataComplete()) {
            // Step 6. Merge web-fragment.xml files into the main web.xml
            // file.
            if (ok) {
                ok = webXml.merge(orderedFragments);
            }

            // Step 7. Apply global defaults
            // Have to merge defaults before JSP conversion since defaults
            // provide JSP servlet definition.
            webXml.merge(defaults);

            // Step 8. Convert explicitly mentioned jsps to servlets
            if (ok) {
                convertJsps(webXml);
            }

            // Step 9. Apply merged web.xml to Context
            if (ok) {
                configureContext(webXml);
            }
         } else {
            webXml.merge(defaults);
            convertJsps(webXml);
            configureContext(webXml);
        }

        // Step 9a. Make the merged web.xml available to other
        // components, specifically Jasper, to save those components
        // from having to re-generate it.
        // TODO Use a ServletContainerInitializer for Jasper
        String mergedWebXml = webXml.toXml();
        sContext.setAttribute(
               org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
               mergedWebXml);
        if (context.getLogEffectiveWebXml()) {
            log.info("web.xml:\n" + mergedWebXml);
        }

        // Always need to look for static resources
        // Step 10. Look for static resources packaged in JARs
        if (ok) {
            // Spec does not define an order.
            // Use ordered JARs followed by remaining JARs
            Set<WebXml> resourceJars = new LinkedHashSet<>();
            if (orderedFragments != null) {
                for (WebXml fragment : orderedFragments) {
                    resourceJars.add(fragment);
                }
            }
            for (WebXml fragment : fragments.values()) {
                if (!resourceJars.contains(fragment)) {
                    resourceJars.add(fragment);
                }
            }
            processResourceJARs(resourceJars);
            // See also StandardContext.resourcesStart() for
            // WEB-INF/classes/META-INF/resources configuration
        }

        // Step 11. Apply the ServletContainerInitializer config to the
        // context
        if (ok) {
            for (Map.Entry<ServletContainerInitializer,
                    Set<Class<?>>> entry :
                        initializerClassMap.entrySet()) {
                if (entry.getValue().isEmpty()) {
                    context.addServletContainerInitializer(
                            entry.getKey(), null);
                } else {
                    context.addServletContainerInitializer(
                            entry.getKey(), entry.getValue());
                }
            }
        }
    }

在這裏插入圖片描述

在這裏插入圖片描述

呼應了Wrapper=Servlet

4.關於組件對內對外屬性

4.1.Connector:是對外的交互的

4.2.Contanier:Engine,Context,Host,Wrapper(Servlet) 是對內交互的

在這裏插入圖片描述

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