0
点赞
收藏
分享

微信扫一扫

tomcat是怎么处理请求的

一、tomcat目录结构

tomcat也是一个应用服务器,下载tomcat源码可以看到tomcat的源码目录如下:



/bin、/conf、/webapps 这些目录就是在我们本地的安装目录可以看到的工具、配置、部署目录,/java目录就是具体的代码实现了

二、tomcat请求处理基本框架

tomcat是个很庞大的项目,这里只会涉及到请求处理部分,并且不涉及具体细节。
注:了解tomcat的大致结构可以先去看下tomcat安装目录中的conf/server.xml文件,文章末尾有样例。

首先,不管是tomcat还是什么其他的web服务器容器,基本功能一定都是监听请求、接受并处理请求,tomcat也是,核心在于请求监听与请求处理。

涉及的接口主要有:


1、Lifecycle

它算是tomcat最顶层的接口,从代码可以看出接口中定义了tomcat的整个生命周期状态一起一些生命周期函数。

package org.apache.catalina;

public interface Lifecycle {

// ----------------------------------------------------- Manifest Constants

/**
 * The LifecycleEvent type for the "component before init" event.
 */
public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";

// --------------------------------------------------------- Public Methods

public void addLifecycleListener(LifecycleListener listener);

public LifecycleListener[] findLifecycleListeners();

public void removeLifecycleListener(LifecycleListener listener);

public void init() throws LifecycleException;

public void start() throws LifecycleException;

public void stop() throws LifecycleException;

public void destroy() throws LifecycleException;

public LifecycleState getState();

public String getStateName();

public interface SingleUse {
}
}

这里重点注意start() 和 stop() 这两个函数,tomcat作为服务器来处理客户端请求,底层也是通过监听socket端口来建立socket连接,然后对请求进行一步步处理的,这里的start() 和 stop() 函数就是用来进行一些开始和结束的操作,包括初始化和终止 socket监听。

2、Connector

tomcat通过Connector来建立socket端口监听,进而接受外部请求进行处理。
说到通过端口来监听socket连接,这就和我们经常接触的tomcat安装目录下的server.xml配置联系起来了,下面是里面的部分配置信息:



可以看出在Connector标签中配置了监听的端口号以及其他一些信息,这个Connector在服务器的代码实现中也有对应的处理类,就是前面说的Connector类。

从server.xml可以理解每个Connector是作为一个连接器,每个Connector对象会监听一个端口,Connector类继承自Lifecycle 接口,监听端口的初始化操作也就在start()方法中实现:




在Connector连接器配置监听的过程中主要有个需要注意的接口ProtocolHandler:

从命名可以看出它是不同协议请求的处理接口,下面是它的所有实现类:

如AbstractEndpoint:它里面封装了socket连接的处理逻辑,下面是它的所有实现类,目前最新版的tomcat都使用NIO的方式。

3、Container

Server.xml中的整个Engine即Container。
Connector进行请求监听,Container是进行连接建立后的请求处理的,它的实现类ContainerBase同样实现了Lifecycle 接口,所以在应用开始时ContainerBase也会执行其start()方法

与Container相关的概念有Engine、Host、Context、Wrapper

***附录:tomcat中默认的server.xml:
<?xml version="1.0" encoding="UTF-8"?>

                                                                                       
<Server port="8005" shutdown="SHUTDOWN">                       //Server代表一个tomcat应用服务器
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <!-- 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">        //Service中包含了多个Connector和一个Container(即Engine),
                                                         相当于将两者封装起来表示这些Connector监听的请求由该Engine处理


    <Connector port="80" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />


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


    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"  
            maxThreads="150" scheme="https" secure="true"  
            clientAuth="false" sslProtocol="TLS"   
        keystoreFile="d:\tomcat.keystore"  
        keystorePass="123456" />  

    <!-- 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">   //服务器引擎,对应源码中的Container,用于处理请求,其中可以包含多个Host,
                                                                                              默认是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"     //主机,就是我们在webapps目录下部署的所有项目,                                                 
            unpackWARs="true" autoDeploy="true">          我们通过主机名+端口号访问我们的应用,主机名就是这里的localhost。

          <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>
举报

相关推荐

0 条评论