【Tomcat源码阅读】核心组件介绍(二)

Tomcat总体结构

Tomcat总体结构用下图来表示

image.png

                                               图片摘自:https://blog.youkuaiyun.com/jiaomingliang/article/details/47393141

从上图可以看到,Tomcat是由Server、Service、Engine、Connerctor、Host、Context组件组成。使用过Tomcat的人对这些组件名是不是有种似曾相识的感觉。回忆一幕幕,好像还是想不起来,哈哈! 好吧,别回忆了,我来告诉你。在Tomcat的conf目录中有一个server.xml文件,打开一看,眼前豁然开朗了,是不是发现server.xml文件中已经包含了上述所有组件。保留server.xml文件中本文将要介绍的核心组件,组件配置及简要介绍如下:

<?xml version="1.0" encoding="UTF-8"?>

<!--
Server标签对应org.apache.catalina.Server接口。
Server元素表示整个Catalina servlet容器。
它的属性代表整个servlet容器的特征。
Server可以包含一个或多个Services,以及顶级命名资源集。
-->
<Server port="8005" shutdown="SHUTDOWN">

    <!--
    Service标签对应org.apache.catalina.Service接口。
    Service包含一个或多个Connectors,它们共享一个Container来处理所有请求。
    -->
    <Service name="Catalina">

        <!--
        Connector代表一个用来接收请求并返回的端
        -->
        <Connector port="8080" protocol="HTTP/1.1"
                   connectionTimeout="20000"
                   redirectPort="8443"/>

        <!--
        Tomcat的Engine实现独立分析请求中包含的HTTP头,并传递它们到适当的主机(虚拟主机)。
        -->
        <Engine name="Catalina" defaultHost="localhost">
            <Host name="localhost" appBase="webapps"
                  unpackWARs="true" autoDeploy="true">


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

Server

Server对应Tomcat源码中的org.apache.catalina.Server接口,其实现类为:org.apache.catalina.core.StandardServer,继承关系图如下图所示:

image.png

  • Server继承至LifeCycle,LifeCycle是一个非常重要的接口,各大组件都继承了这个接口,用于管理tomcat的生命周期,比如init、start、stop、destory;另外,它使用了观察者模式,LifeCycle是一个监听者,它会向注册的LifecycleListener观察者发出各种事件
  • Server除了定义了一些get、set方法用于操作配置外,还定义了addService、findServices、removeService等方法用于操作Service对象,由此也可以看出Server和Serivce组件的关系。

Service

Service对应Tomcat源码中的org.apache.catalina.Service接口,其实现类为:org.apache.catalina.core.StandardService,继承关系如下图所示:

image.png

Service的继承关系与Server继承关系很相似,除自身定义的接口其他都是一样。StandardService部分源码如下:

// ----------------------------------------------------- Instance Variables
/**
* The name of this service.
*/
private String name = null;
/**
* The <code>Server</code> that owns this Service, if any.
*/
private Server server = null;
/**
* The set of Connectors associated with this Service.
*/
protected Connector connectors[] = new Connector[0];
/**
* The list of executors held by the service.
*/
protected final ArrayList<Executor> executors = new ArrayList<>();

private Engine engine = null;

从源码中可以看到Service组件的内部结构

  • 持有Engine实例
  • 持有Server实例
  • 可以管理多个Connector实例
  • 持有Executor引用

Connector

Connector对应Tomcat源码中的org.apache.catalina.connector.Connector类,继承关系如下图所示:

image.png

Connector是Tomcat中监听TCP端口的组件,server.xml默认定义了两个Connector,分别用于监听http、ajp端口。

http监听配置

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

http对应的Connector配置如上所示,其中port用于指定监听端口;protocol用于指定http协议的版本,还可以支持2.0;connectionTimeout定义了连接超时时间,单位是毫秒;redirectPort是SSL的重定向端口,它会把请求重定向到8443这个端口

AJP监听配置

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Apache jserver协议(AJP)是一种二进制协议,它可以将来自web服务器的入站请求发送到位于web服务器后的应用服务器。如果我们希望把Tomcat集成到现有的(或新的)Apache http server中,并且希望Apache能够处理web应用程序中包含的静态内容,或者使用Apache的SSL处理,我们便可以使用该协议。但是,在实际的项目应用中,AJP协议并不常用,大多数应用场景会使用nginx+tomcat实现负载。

下面看一下Connector构造函数源码如下:

// ------------------------------------------------------------ Constructor

/**
 * Defaults to using HTTP/1.1 NIO implementation.
 */
public Connector() {
    this("org.apache.coyote.http11.Http11NioProtocol");
}


public Connector(String protocol) {
    boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
            AprLifecycleListener.getUseAprConnector();

    if ("HTTP/1.1".equals(protocol) || protocol == null) {
        if (aprConnector) {
            protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";
        } else {
            protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
        }
    } else if ("AJP/1.3".equals(protocol)) {
        if (aprConnector) {
            protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol";
        } else {
            protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol";
        }
    } else {
        protocolHandlerClassName = protocol;
    }

    // Instantiate protocol handler
    ProtocolHandler p = null;
    try {
        Class<?> clazz = Class.forName(protocolHandlerClassName);
        p = (ProtocolHandler) clazz.getConstructor().newInstance();
    } catch (Exception e) {
        log.error(sm.getString(
                "coyoteConnector.protocolHandlerInstantiationFailed"), e);
    } finally {
        this.protocolHandler = p;
    }

    // Default for Connector depends on this system property
    setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));
}

从构造函数中可以看到Tomcat实现了HTTP/1.1和AJP/1.3两种协议,而且每个协议都两种实现方式。默认协议是:HTTP/1.1。

Container

Container对应Tomcat源码中的org.apache.catalina.Container接口,该接口定义了容器的API,Container部分源码如下:

/**
 * 添加一个容器添加到当前容器
 */
public void addChild(Container child);

/**
 * 根据名称获取当前容器的子容器
 */
public Container findChild(String name);

/**
 * 获取当前容器所有子容器
 */
public Container[] findChildren();

/**
 * 删除当前容器指定的子容器
 */
public void removeChild(Container child);

它包含四种不同的容器:

  • Engine,表示整个Catalina的servlet引擎
  • Host,表示一个拥有若干个Context的虚拟主机
  • Context,表示一个Web应用,一个context包含一个或多个wrapper
  • Wrapper,表示一个独立的servlet

Container是用来处理来自客户端的servlet请求,并且返回响应的对象。继承关系如下图:

image.png

Engine、Host、Context、Wrapper都有一个默认的实现类StandardXXX,均继承至ContainerBase。此外,一个容器还包含一系列的Lodder、Logger、Manager、Realm和Resources等。一个容器可以有一个或多个低层次上的子容器,并且一个Catalina功能部署并不一定需要全部四种容器。一个Context有一个或多个wrapper,而wrapper作为容器层次中的最底层,不能包含子容器。

Engine

Engine对应Tomcat源码中的org.apache.catalina.Engine接口,其实默认现类为:org.apache.catalina.core.StandardEngine,继承关系如下图所示:

image.png

Engine表示Catalina的Servlet引擎,如果使用了Engine的话,则它是Catalina的顶层容器,因此在StandardEngine的setParent()方法中直接抛出的异常。

/**
 * Disallow any attempt to set a parent for this Container, since an
 * Engine is supposed to be at the top of the Container hierarchy.
 *
 * @param container Proposed parent Container
 */
@Override
public void setParent(Container container) {

    throw new IllegalArgumentException
        (sm.getString("standardEngine.notParent"));

}

Host

Host对应Tomcat源码中的org.apache.catalina.Host接口,其默认实现类为:org.apache.catalina.core.StandardHost,继承关系如下图所示:

image.png

Host定义了一个虚拟主机,正所谓虚拟主机,当然是可以用来部署应用程序的,Tomcat的Host也是如此。它在server.xml中定义了一个localhost的Host,应用根目录在webapps下面,默认是支持解压重新部署的。

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

Context

Context对应Tomcat源码中的org.apache.catalina.Context接口,其默认实现类为:org.apache.catalina.core.StandardContext,继承关系如下图所示:

image.png

Context代表一个独立的web应用,针对每个Context,tomcat都是使用不同的Classloader避免类冲突。如果我们希望使用一个自定义的目录作为部署路径的话,可以在server.xml中新增Context即可

 

 

 

【ZhoujEndless】至此!感觉您的阅读,如有任何问题,欢迎打扰!如有表述错误,劳烦指出!

参考资料:https://blog.youkuaiyun.com/dwade_mia/article/details/79051404

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值