在看源码之前,我们首先得了解Tomcat的结构组成,并且了解它每个组件的作用,这样我们看才不会一脸懵逼。
tomcat的总体架构如下图所示(摘自https://blog.csdn.net/Dwade_mia/article/details/79051404)
如上图所示:Tomcat由Server、Service、Engine、Connector、Host、Context、Wrapper组成,图中由括号有s的组件,代表在Tomcat实例中可以出现多个。
1、Server:由1-n个Service组成,让其他程序可以访问Service集合,提供对Service集合的管理【增删改查】。还提供Tomcat初始化、Tomcat关闭等功能
2、Service:它由单个Container【一般是Engine】、多个Connector组成。只是在Container和Connector外,多包了一层,提供对这几个组件的管理。还有提供一个桥梁,让Connector可以访问Container。
3、Connector:负责接收TCP连接请求,创建Request/Response,分配请求处理线程,将创建的对象交给Container处理。(Connector通过Service可以获取到Container)
4、Container是容器的父接口,由四个容器组成,分别是Engine,Host,Context,Wrapper。其中Engine包含Host,Host包含Context,Content包含Wrapper,一个Servlet class对应一个Wrapper。
5、Engine:Container的顶级组件。有了Engine,请求的处理过程就变成,Connector接收请求,将请求交给Engine,Engine找到对应的Host,Host拿到请求后查找对应的项目【也就是Context】,Context根据对应的Url找到对应的Wrapper【也就是Servlet】,最后Servlet对请求做出相应的处理
6、Host:顾名思义:虚拟主机,提供一台主机,有多个域名可以访问,当然默认是localhost,配置了Host域名,也要在hosts文件添加映射,要不不起作用。它还有提供自动解压War包、指定部署路径【也就是说:项目部署不一定要防在webapps下,可以自定义配置】等功能
7、Context:对应一个Web项目,也可以理解为多个Servlet的集合。譬如说webapps下有两个项目,那么则有2个Context组件。每个Context的Servlet集合是分开的,它的功能主要是对Servlet的管理、Session管理等功能。
8、Wrapper:它就是我们平时使用的Servlet了。它负责Servlet生命管理、初始化、执行、资源回收等
像上面的组件都可以在server.xml中,可以找到对应的标签【标签对应中组件,可以这样理解】
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<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>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<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:org.apache.catalina.Server
它的实现类是:org.apache.catalina.core.StandardServer
public interface Server extends Lifecycle {
public NamingResourcesImpl getGlobalNamingResources();
public void setGlobalNamingResources(NamingResourcesImpl globalNamingResources);
public javax.naming.Context getGlobalNamingContext();
public int getPort();
public void setPort(int port);
public String getAddress();
public void setAddress(String address);
public String getShutdown();
public void setShutdown(String shutdown);
public ClassLoader getParentClassLoader();
public void setParentClassLoader(ClassLoader parent);
public Catalina getCatalina();
public void setCatalina(Catalina catalina);
public File getCatalinaBase();
public void setCatalinaBase(File catalinaBase);
public File getCatalinaHome();
public void setCatalinaHome(File catalinaHome);
public void await();
public Service findService(String name);
public Service[] findServices();
public void removeService(Service service);
public Object getNamingToken();
}
由上面可知,Server继承Lifecycle类【上面所有的组件,都是直接继承Lifecycle类或者间接继承Lifecycle类】;Lifecycle类它是非常重要的一个接口,用于管理Tomcat的生命中期,例如init、start、stop、destory;另外它使用了观察者模式,Lifecycle是一个监听者,它会向注册到的LifecycleListener观察者发出各种事件,后面会抽出一节来讲。
Server提供了对Service管理、包括getCatalina、getCatalinaHome等功能
Service:org.apache.catalina.Service
它的实现类为:org.apache.catalina.core.StandardService
public interface Service extends Lifecycle {
public Engine getContainer();
public void setContainer(Engine engine);
public String getName();
public void setName(String name);
public Server getServer();
public void setServer(Server server);
public ClassLoader getParentClassLoader();
public void setParentClassLoader(ClassLoader parent);
public String getDomain();
public void addConnector(Connector connector);
public Connector[] findConnectors();
public void removeConnector(Connector connector);
public void addExecutor(Executor ex);
public Executor[] findExecutors();
public Executor getExecutor(String name);
public void removeExecutor(Executor ex);
Mapper getMapper();
}
由上面可知,它具有以下功能
由Tomcat的server.xml配置文件可知默认会初始化两个Connector,一个是负责Http请求的Connector,一个是负责AJP请求的Connector
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
Container:org.apache.catalina.Container
它对应的四种不同的组件:
Engine、Host、Context、Wrapper都有一个默认的实现类StandardXXX,均继承至ContainerBase,提供了一些常用的Container接口的实现。
public abstract class ContainerBase extends LifecycleMBeanBase
implements Container {
```省略
}
一个容器可以有一个或多个低层次的子容器,并且一个Catalina功能部署并不一定需要全部四种容器。一个Context有一个或多个wrapper,而wrapper作为容器层次中的最底层,不能包含子容器。从一个容器添加到另一容器中可以使用在Container接口中定义的addChild()方法:
public void addChild(Container child);
删除一个容器可以使用Container接口中定义的removeChild()方法:
public void removeChild(Container child);
另外容器接口支持子接口查找和获得所有子接口集合的方法findChild和findChildren方法:
public Container findChild(String name);
public Container[] findChildren();
Engine:org.apache.catalina.Engine
它的实现类是:org.apache.catalina.core.StandardEngine
public interface Engine extends Container {
public String getDefaultHost();
public void setDefaultHost(String defaultHost);
public String getJvmRoute();
public void setJvmRoute(String jvmRouteId);
public Service getService();
public void setService(Service service);
}
对应server.xml
<Engine name="Catalina" defaultHost="localhost">
```省略
</Engine>
由上面可知:
Host:它表示一个虚拟主机。正所谓虚拟主机,当然是可以用来部署应用程序的,Tomcat的Host也是如此。它在server.xml中定义了一个localhost的Host,应用根目录在webapps下面,默认是支持解压重新部署的
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"/>
name:虚拟主机名
appBase:部署目录,也叫根目录
unpackWAR:true,自动解压war包,false,反之
autoDeploy:true,自动部署,false,反之
Context:一个独立的web应用,每个Context,tomcat都是使用不同的Classloader避免类冲突。如果我们希望使用一个自定义的目录作为部署路径的话,可以在server.xml中新增Context即可
<Context path="/static" docBase="D:/static" reloadable="true"></Context>