前言
夫夷以近,则游者众;险以远,则至者少。而世之奇伟、瑰怪,非常之观,常在于险远,而人之所罕至焉,故非有志者不能至也。有志矣,不随以止也,然力不足者,亦不能至也。有志与力,而又不随以怠,至于幽暗昏惑而无物以相之,亦不能至也。然力足以至焉,于人为可讥,而在己为有悔;尽吾志也而不能至者,可以无悔矣,其孰能讥之乎?此余之所得也。
选自《游褒禅山记》
全局组件图
元素说明
首先来看看tomcat的一个重要配置文件,server.xml,精简结构如下
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Context path="/test" docBase="D:\Program Files\test.war" reloadable="true"/>
</Host>
</Engine>
</Service>
</Server>
根据配置文件可以看出,tomcat架构中的主要元素为server,service,connector,engine,host,context。
- server:代表tomcat服务;
- service:用来整合connector和engine,connector可以有多个,对应多个协议,engine只能有一个;
- connector:不同协议对应不同的connector,接受请求,返回响应;
- engine:用来处理connector接收到的请求,经过处理后,返回给connector;
- host:代表一个虚拟主机,一般不会配置多个,在engine中有个配置defaultHost,必定会有一个host的name设置为与defaultHost对应的值,是请求的默认处理器;host的默认路径是webapps,也就是说,在tomcat/webapps中,每一个文件夹里有web.xml文件的都是一个context;
- context:一个context代表一个应用,比如配置中的test.war,就是一个应用,凡是经过其父节点【host】传过来的,路径是/test/*请求,都会经由此context进行处理。
service中connector面向用户请求,用来接收请求和返回答复;containner用来处理请求,封装答复;
源码对照
这里大概说一下Tomcat源代码中,对这些元素的定义。
源代码中,给这几个元素提供了默认实现,分别是StandardServer,StandardService,Connector,StandardEngine,StandardHost,StandardContext,StandardWrapper,其中StandardWrapper对应一个servlet,用来处理请求中具体的业务逻辑;
一个请求的大概路径如下
// HTTP1.1协议收到请求,交由AbstractProcessorLight类进行验证和处理
AbstractProtocol.ConnectionHandler.process(SocketWrapperBase<S> wrapper, SocketEvent status) {
AbstractProcessorLight.process();
}
// 验证请求
AbstractProcessorLight. process(SocketWrapperBase<?> socketWrapper, SocketEvent status){
// process it now.
state = service(socketWrapper);
return state;
}
// 交由Adapter适配器进行处理
Http11Processor.service(SocketWrapperBase<?> socketWrapper){
// Process the request in the adapter
getAdapter().service(request, response);
}
// 转发给containner调用链处理具体逻辑,调用链下一回再进行说明
CoyoteAdapter.service(org.apache.coyote.Request req, org.apache.coyote.Response res){
// Calling the container
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
}
engine、host、context和wrapper在源代码中当成Container来初始化,下面是各个元素在代码中的依赖关系;
server
一个server对应多个service,源码类:StandardServer
/**
* The set of Services associated with this Server.
*/
private Service services[] = new Service[0];
public void addService(Service service) {
// 绑定server
service.setServer(this);
// 加入service数组
services[services.length] = service;
// 启动service
service.start();
}
service
一个service对应多个connector,对应一个engine,源码类:StandardService
- 添加connector
/**
* The set of Connectors associated with this Service.
*/
protected Connector connectors[] = new Connector[0];
public void addConnector(Connector connector) {
// 绑定service
connector.setService(this);
// 加入connectors数组
connectors[connectors.length] = connector;
// 启动
connector.start();
}
- 添加Engine,一个service对应一个引擎
private Engine engine = null;
public void setContainer(Engine engine) {
this.engine = engine;
// 绑定service
this.engine.setService(this);
// 启动引擎
this.engine.start();
}
engine
一个engine对应多个host,源码类:StandardEngine
最终在父类ContainerBase的方法addChildInternal中启动child,child.start()。
public void addChild(Container host) {
if (!(child instanceof Host))
throw new IllegalArgumentException
(sm.getString("standardEngine.notHost"));
// 调用父类ContainerBase添加容器,并启动
super.addChild(child);
}
host
一个host对应多个context,源码类:StandardHost
最终在父类ContainerBase的方法addChildInternal中启动child,child.start()。
public void addChild(Container child) {
child.addLifecycleListener(new MemoryLeakTrackingListener());
if (!(child instanceof Context))
throw new IllegalArgumentException
(sm.getString("standardHost.notContext"));
// 调用父类ContainerBase添加容器,并启动
super.addChild(child);
}
context
一个context对应多个wrapper,源码类:StandardContext
最终在父类ContainerBase的方法addChildInternal中启动child,child.start()。
public void addChild(Container child) {
// Global JspServlet
Wrapper oldJspServlet = null;
if (!(child instanceof Wrapper)) {
throw new IllegalArgumentException
(sm.getString("standardContext.notWrapper"));
}
...
// 调用父类ContainerBase添加容器,并启动
super.addChild(child);
...
}
wrapper
一个wrapper对应一个servlet,处理请求中具体的业务逻辑,tomcat启动时执行初始化。源码类:StandardWrapper
/**
* Wrapper里的对应的servlet类名
*/
protected String servletClass = null;
/**
* Wrapper里的对应的servlet实例【唯一】
*/
protected volatile Servlet instance = null;
@Override
public void setServletClass(String servletClass) {
// 设置servlet类名,tomcat启动时执行
String oldServletClass = this.servletClass;
this.servletClass = servletClass;
support.firePropertyChange("servletClass", oldServletClass,
this.servletClass);
if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) {
isJspServlet = true;
}
}
@Override
public void setServlet(Servlet servlet) {
// 设置实例,tomcat启动时执行
instance = servlet;
}