前言
Tomcat作为Java开发者接触过最重要的web容器,在启动和处理请求过程中做了海量的事情,初级开发者很少关心,使用SpringMvc之类上层框架一带而过,然而这些部分是Java和网络集大成之作,笔者要带着大家走一遍一次请求,加深tomcat的认知。最好先调试好Tomcat源码
Tomcat基础架构
BootStrap和Catalina
BootStrap
BootStrap就是Tomcat的main函数所在位置,在使用过程中执行脚本catlina.sh或者bat文件即可执行java命令并调用BootStrap的main函数实现tomcat的启动
public static void main(String args[]) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
// When running as a service the call to stop will be on a new
// thread so make sure the correct class loader is used to
// prevent a range of class not found exceptions.
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
......
}
Catalina
BootStrap是服务器的入口, 会通过start、stop、stopServer、stopServer等反射调用Catalina的对应方法
public void stopServer() throws Exception {
Method method =
catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
method.invoke(catalinaDaemon, (Object []) null);
}
Tomcat的核心配置文件server.xml
先来看一下tomcat的容器结构
tomcat容器有多层,Server、service、Engine、Host、Context等,图中有省略
比如一个名称为mytomcat的web项目,对应到Container部分,Context名称就是mytomcat
再看一下Tomcat的配置文件server.xml
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener SSLEngine="on"
className="org.apache.catalina.core.AprLifecycleListener" />
<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" />
<GlobalNamingResources>
<Resource auth="Container" description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase"
pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector URIEncoding="UTF-8" connectionTimeout="20000"
port="80" protocol="HTTP/1.1" redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase" />
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost"
unpackWARs="true">
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log."
suffix=".txt" />
</Host>
</Engine>
</Service>
在启动tomcat的时候,catalina的load方法,会读取server.xml文件的内容,通过Digester组件把server.xml解析成Server对象,并且把Server变成Catalina的成员变量。
我们看一下catalina的load方法中digester.parse()方法执行后的容器代码结构
这样的话,Tomcat的容器的层级结构就建立起来了。
网络处理部分
Connector
tomcat可以处理多种协议,统一使用Connector组件来实现,在tomcat中一个Service可以对应多个Connector
ProtocolHandler
connector中有个很重要的成员变量protocolHandler, 用来实现多种协议的解析,
比如http协议。基于tcp做集群的AJP协议
Endpoint
AbstractEndpoint是Tcp的处理入口,并且持有Executor;Connector的executor和ProtocolHandler的线程池都是使用这个executor
当有网络任务到来的时候,tomcat会使用这个线程池来处理socket事件
Acceptor 和 Poller
Acceptor是封装新连接的任务,Endpoint使用单独的线程维护 Poller 是java NIO中Selector的封装,当新连接到来时唤醒Acceptor线程注册pollerEvent事件来监听连接
Poller的实现是java的Selector
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。