共计 3165 个字符,预计需要花费 8 分钟才能阅读完成。
前言
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