前言
tomcat源码都是围绕着server.xml这个配置文件展开来看的,所以我们分析它的源码也需要从它开始入手。
概览
Tomcat的组织结构很简单,下面一张图能够清晰的展示出来。
Server是Tomcat中最顶层的容器,代表着整个服务器,一个Server可以包含至少一个Service,用于具体提供服务。
Service主要包含两个核心组件:Connector和Container。
Connector组件负责处理请求监听,一个Connector与一个TCP端口绑定,接受Socket请求并将请求封装成Request和Response
Container组件负责处理请求处理,用于封装和管理Servlet,以及具体处理Request请求
至于具体的请求,我们通过源码说明。
配置文件源码分析
每个组件都能够在源码中体现出来,这里我提供一份自己添加了注释的配置文件,可以参照理解。
并且我会在下面对核心组件进行具体分析。
<?xml version='1.0' encoding='utf-8'?>
<!--
Server是一个顶级组件,代表了一个Tomcat实例,一个JVM进程中只能有一个Server实例。
Tomcat提供了一个实现了 org.apache.catalina.Server接口的 org.apache.catalina.core.StandardServer默认类,读取Server元素配置。
Server是配置文件中的最外层元素,支持以下属性:
className:指定要使用的实现类(必须实现org.apache.catalina.Server接口)名称。如果不指定,默认使用标准实现类StandardServer。
address:等待shutdown命令的服务器IP地址,默认是localhost。
port:等待shutdown命令的监听端口,如果设置为-1,表示关闭shutdown端口。
shutdown:指定终止Tomcat服务器运行时,发给Tomcat服务器的shutdown监听端口的字符串.该属性必须设置 。
-->
<Server port="8015" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on"/>
<Listener className="org.apache.catalina.core.JasperListener"/>
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<!--定义的全局JNDI资源-->
<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>
<!--Server元素中可以有一个或多个Service,每个Service关联了多个Connector和一个Engine。
Service支持两个属性:
className:指定要使用的实现类(必须实现org.apache.catalina.Service接口)名称。如果不指定,默认使用标准实现类StandardService。
name:Service的名称,在同一个Server元素中必须唯一,默认是Catalina。
-->
<Service name="Catalina">
<!--Connector负责处理请求监听,一个Connector与一个TCP端口绑定,接受请求并将请求封装成Request和Response,Service中默认包含两个Connector。
Connector支持四个属性:
port:属性指定监听端口,默认8080端口,可修改为1024-65535间的任意一个端口
protocol:支持协议
connectionTimeout:定义连接器等待时间,默认20秒
redirectPort:SSL请求会重定向到8443端口
-->
<!--HTTP/1.1:处理HTTP请求,此连接器使Tomcat可以作为HTTP服务器使用。-->
<Connector port="8090" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8453"/>
<!--AJP/1.3:Apache JServ 协议处理Tomcat与Apache之间的通信。Tomcat核心功能是解析Servlet,html和图片解析功能相对其他HTTP服务器较弱(如Apache HTTP Server),所以,一般都是集成使用,Apache处理静态页面请求,Tomcat处理Servlet/JSP请求。-->
<Connector port="8019" protocol="AJP/1.3" redirectPort="8453"/>
<!--Container负责处理请求处理,有四个子容器:Engine、Host、Context和Wrapper,他们之间是父子包含关系。-->
<!--一个Service只有一个Engine,表示整个Servlet引擎,其主要作用是执行业务逻辑;从HTTP Connector接收HTTP请求,并且会根据主机名/IP地址交由相应的主机处理请求。-->
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
<!--Host,代表一个站点,也可以叫虚拟主机,一个Engine下面可以包含一个或者多个Host,即一个Tomcat实例可以配置多个虚拟主机-->
<!--appBase:定义了应用程序的根目录,默认是webapps-->
<!--unpackWARS:定义了是否解压webapps中的WAR文件,如果指定为“false”,会从WAR文件直接运行程序,执行较慢-->
<!--autoDeploy:把应用程序直接拖到webapps目录下,是否自动运行-->
<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"/>
<!--
Context,代表一个应用程序
path:访问项目时的URL,加在localhost:8080后
docBase:path对应的项目目录
reloadable:监视 /WEB-INF/classes/ 和 /WEB-INF/lib目录中的类文件,更改后自动重载应用程序,
生成环境不建议使用,默认为“false”
-->
<Context path="/image" docBase="/opt/file/img" reloadable="false"></Context>
<!--Wrapper针对的是每个具体的servlet-->
</Host>
</Engine>
</Service>
</Server>
tomcat的核心组件
介绍下tomcat的核心组件Connector组件和Container组件
Connector组件
Connector组件负责处理请求监听,一个Connector与一个TCP端口绑定,接受Socket请求并将请求封装成Request和Response对象,然后将产生的 Request 和 Response 对象传给处理Engine(Container中的一部分),真正处理请求的是Engine。
Service中默认包含两个Connector,HTTP协议和AJP协议,HTTP协议接收http请求,使Tomcat可以作为HTTP服务器使用。AJP协议处理Tomcat和Apache服务器之间的请求。
Connector在Tomcat中的设计如图所示。这里不深入讨论,后续再深入。
Container组件
Container负责处理请求处理,Container是容器的父接口,有四个子容器:Engine、Host、Context和Wrapper,他们之间是父子包含关系。体系结构如下:
- Engine 容器
一个Service只有一个Engine,表示整个Servlet引擎,其主要作用是执行业务逻辑;从HTTP Connector接收HTTP请求,并且会根据主机名/IP地址交由相应的主机处理请求。uml类图如下
- Host 容器
代表一个站点,也可以叫虚拟主机,一个Engine下面可以包含一个或者多个Host,即一个Tomcat实例可以配置多个虚拟主机,uml类图如下。
- Context 容器
Context 代表 Servlet 的 Context,它具备了 Servlet 运行的基本环境,理论上只要有 Context 就能运行 Servlet 了。简单的 Tomcat 可以没有 Engine 和 Host。Context 最重要的功能就是管理它里面的 Servlet 实例,Servlet 实例在 Context 中是以 Wrapper 出现的,uml类图如下。
- Wrapper 容器
Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。Wrapper 是最底层的容器,它没有子容器了,所以调用它的 addChild 将会报错。
Wrapper 的实现类是 StandardWrapper,StandardWrapper 还实现了拥有一个 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 将直接和 Servlet 的各种信息打交道。uml类图如下。
tomcat其他组件
Tomcat 还有其它重要的组件,如安全组件 security、logger 日志组件、session、mbeans、naming 等其它组件。这些组件共同为 Connector 和 Container 提供必要的服务。
小结
现在我们了解了,tomcat的整体结构大概是这个样子。
整个启动流程也是很标准化的,入口是BootStrap,统一按照生命周期管理接口Lifecycle的定义进行启动。首先,调用init()方法逐级初始化,接着调用start()方法进行启动,同时,每次调用伴随着生命周期状态变更事件的触发。
每一级组件除完成自身的处理外,还有负责调用子组件的相关调用,组件和组件之间是松耦合的,可以通过配置进行修改。
学习tomcat的源码,参考了https://blog.csdn.net/w1992wishes/article/details/79242797这篇文章,感觉写的不错,可以参考下。