tomcat源码分析—请求过程
Tomcat作为Web服务器可以处理浏览器的HTTP请求,并接交给相应的Servlet,这个过程tomcat都做了什么,是怎么处理请求,以下对请求处理细节进行分析。
CONNECTOR的初始化
Tomcat中有很多容器,包括Server、Service、Connector等。其中Connector正是与HTTP请求处理相关的容器;
tomcat中Connector的实现有以下三种:
- Http Connector:基于HTTP协议,负责建立HTTP连接。它又分为BIO Http Connector与NIO Http Connector两种,后者提供非阻塞IO与长连接Comet支持。
- AJP Connector:基于AJP协议,AJP是专门设计用于Tomcat与HTTP服务器通信定制的协议,能提供较高的通信速度和效率。如与Apache服务器集成时,采用这个协议。
- APR HTTP Connector:用C实现,通过JNI调用的。主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能。现在这个库已独立出来可用在任何项目中。由于APR性能较前两类有很大提升,所以目前是Tomcat的默认Connector。
Connector是一个容器,并且继承了LifecycleMBeanBase,所以既有Lifecycle的特征,有可以通过JMX进行管理。
Connector的构造方法如下:
protected String protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
public Connector(String protocol) {
setProtocol(protocol);
ProtocolHandler p = null; // Instantiate protocol handler
try {
Class<?> clazz = Class.forName(protocolHandlerClassName);
p = (ProtocolHandler) clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
log.error(sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"), e);
} finally {
this.protocolHandler = p;
}
if (!Globals.STRICT_SERVLET_COMPLIANCE) {
URIEncoding = "UTF-8";
URIEncodingLower = URIEncoding.toLowerCase(Locale.ENGLISH);
}
}
这个构造方法有一个protocol参数,这个参数可以在server.xml中的Connector 节点来配置,如果不配置,默认的是 Http11NioProtocol
setProtocol方法根据protocol参数的不同,来设置设置protocolHandlerClassName属性
public void setProtocol(String protocol) {
if (AprLifecycleListener.isAprAvailable()) {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
} else {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
}
} else {
if ("HTTP/1.1".equals(protocol)) {
setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
} else if ("AJP/1.3".equals(protocol)) {
setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
} else if (protocol != null) {
setProtocolHandlerClassName(protocol);
}
}
}
Connector的构造方法是在 ConnectorCreateRule 的的begin方法中来调用的。
Digester作为解析server.xml 的的组件,<Connector>节点的时候,创建Digester对象时会生成一个ConnectorCreateRule对象,在生成Digester的createStartDigester()方法
digester.addRule("Server/Service/Connector", new ConnectorCreateRule());
Digester在解析<Connector>节点后,会执行ConnectorCreateRule对象的startElement方法,startElement中会调用Rule的begin(String namespace, String name, Attributes attributes)方法,
@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes list) throws SAXException {
boolean debug = log.isDebugEnabled();
if (saxLog.isDebugEnabled()) {
saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + qName + ")");
}
// Parse system properties
list = updateAttributes(list);
// Save the body text accumulated for our surrounding element
bodyTexts.push(bodyText);
bodyText = new StringBuilder();
// the actual element name is either in localName or qName, depending on whether the parser is namespace aware
String name = localName;
if ((name == null) || (name.length() < 1)) {
name = qName;
}
// Compute the current matching rule
StringBuilder sb = new StringBuilder(match);
if (match.length() > 0) {
sb.append('/');
}
sb.append(name);
match = sb.toString();
if (debug) {
log.debug(" New match='" + match + "'");
}
// Fire "begin" events for all relevant rules
List<Rule> rules = getRules().match(namespaceURI, match);
matches.push(rules);
if ((rules != null) && (rules.size() > 0)) {
for (int i = 0; i < rules.size(); i++) {
try {
Rule rule = rules.get(i);
if (debug) {
log.debug(" Fire begin() for " + rule);
}
rule.begin(namespaceURI, name, list);
} catch (Exception e) {
log.error("Begin event threw exception", e);
throw createSAXException(e);
} catch (Error e) {
log.error("Begin event threw error", e);
throw e;
}
}
} else {
if (debug) {
log.debug(" No rules found matching '" + match + "'.");
}
}
}
Rule的begin方法会生产一个Connector对象,
@Override
public void begin(String namespace, String name, Attributes attributes) throws Exception {
Service svc = (Service) digester.peek();
Executor ex = null;
if (attributes.getValue("executor") != null) {
ex = svc.getExecutor(attributes.getValue("executor"));
}
Connector con = new Connector(attributes.getValue("protocol"));
if (ex != null)
_setExecutor(con, ex);
digester.push(con);
}
Connector对象生成完后,需要调用 initInternal()方法。
@Override
protected void initInternal() throws LifecycleException {
super.initInternal();
// Initialize adapter
adapter = new CoyoteAdapter(this);
protocolHandler.setAdapter(adapter);
// Make sure parseBodyMethodsSet has a default
if (null == parseBodyMethodsSet) {
setParseBodyMethods(getParseBodyMethods());
}
if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerNoApr", getProtocolHandlerClassName()));
}
try {
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}
先调用父类的initInternal()d的方法初始化jmx.
构造网络处理协议 CoyoteAdapter:用当前对象来构造一个CoyoteAdapter对象 ,并且将其设置为ProtocolHandler的Adapter
ProtocolHandler协议处理器,根据不同d的协议,比如根据上面的http, ajp来构建不同的协议处理器来处理数据,但它实际不负责这个功能,而是将其交给org.apache.coyote.Adapter来完成,其中Adapter 在tomcat中的唯一实现就是 CoyoteAdapter ,
ProtocolHandlerd的实现以及继承关系如下:

Http11Protocol是Connector的默认处理协议,用来处理HTTP1.1网络协议的请求。
参考:http://www.cnblogs.com/jiaan-geng/p/4875249.html

浙公网安备 33010602011771号