Tomcat总体结构
Tomcat总体结构用下图来表示
图片摘自: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 "%r" %s %b"/>
</Host>
</Engine>
</Service>
</Server>
Server
Server对应Tomcat源码中的org.apache.catalina.Server接口,其实现类为:org.apache.catalina.core.StandardServer,继承关系图如下图所示:
- 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,继承关系如下图所示:
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类,继承关系如下图所示:
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请求,并且返回响应的对象。继承关系如下图:
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,继承关系如下图所示:
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,继承关系如下图所示:
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 "%r" %s %b" />
</Host>
Context
Context对应Tomcat源码中的org.apache.catalina.Context接口,其默认实现类为:org.apache.catalina.core.StandardContext,继承关系如下图所示:
Context代表一个独立的web应用,针对每个Context,tomcat都是使用不同的Classloader避免类冲突。如果我们希望使用一个自定义的目录作为部署路径的话,可以在server.xml中新增Context即可
【ZhoujEndless】至此!感觉您的阅读,如有任何问题,欢迎打扰!如有表述错误,劳烦指出!
参考资料:https://blog.youkuaiyun.com/dwade_mia/article/details/79051404