tomcat源码分析—请求过程

Tomcat作为Web服务器可以处理浏览器的HTTP请求,并接交给相应的Servlet,这个过程tomcat都做了什么,是怎么处理请求,以下对请求处理细节进行分析。 

CONNECTOR的初始化

Tomcat中有很多容器,包括Server、Service、Connector等。其中Connector正是与HTTP请求处理相关的容器;

tomcat中Connector的实现有以下三种:

  1. Http Connector:基于HTTP协议,负责建立HTTP连接。它又分为BIO Http Connector与NIO Http Connector两种,后者提供非阻塞IO与长连接Comet支持。
  2. AJP Connector:基于AJP协议,AJP是专门设计用于Tomcat与HTTP服务器通信定制的协议,能提供较高的通信速度和效率。如与Apache服务器集成时,采用这个协议。
  3. 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

 
posted @ 2016-11-03 19:35  南极山  阅读(341)  评论(0)    收藏  举报