专栏名称: 预流
敲代码的
目录
相关文章推荐
美团技术团队  ·  空降香港!美团无人机率先在港启航 ·  2 天前  
架构师之路  ·  DeepSeek开源V3/R1架构设计思路, ... ·  3 天前  
架构师之路  ·  第6篇10W+,原来不跳舞也可以... ·  4 天前  
架构师之路  ·  一个无价的DeepSeek闭门会,送10张门 ... ·  昨天  
架构师之路  ·  总有人问,出海怎么用DeepSeek满血版( ... ·  4 天前  
51好读  ›  专栏  ›  预流

Tomcat 7 的一次请求分析(一)处理线程的产生

预流  · 掘金  ·  · 2018-02-01 02:14

正文

在默认的配置下Tomcat启动好之后会看到后台上总共有6个线程在运行。其中1个用户线程,剩下5个为守护线程(如下图所示)。

如果你对用户线程、守护线程等概念不熟悉,请参看前一篇文章—— Tomcat 7 服务器关闭原理 。 这里重点关注以 http-bio-8080 开头的两个守护线程(即 http-bio-8080-Acceptor-0 和 http-bio-8080-AsyncTimeout ),因为这是我们在 Tomcat 的默认配置下发布 web 应用时实际处理请求的线程。先看下这两个线程在容器启动时是如何产生和启动的。

在前面将 Tomcat 启动的系列文章中看到 Tomcat 容器启动时会用 Digester 读取 server.xml 文件产生相应的组件对象并采取链式调用的方式调用它们的 init 和 start 方法,在 Digester 读取到 server.xml 中的 connector 节点时是这么处理的:

        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());
        digester.addRule("Server/Service/Connector",
                         new SetAllPropertiesRule(new String[]{"executor"}));
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.connector.Connector");

以上代码见 org.apache.catalina.startup.Catalina 类的 366 到 372 行。所以在碰到 server.xml 文件中的 Server/Service/Connector 节点时将会触发 ConnectorCreateRule 类的 begin 方法的调用:

     1	    public void begin(String namespace, String name, Attributes attributes)
     2	            throws Exception {
     3	        Service svc = (Service)digester.peek();
     4	        Executor ex = null;
     5	        if ( attributes.getValue("executor")!=null ) {
     6	            ex = svc.getExecutor(attributes.getValue("executor"));
     7	        }
     8	        Connector con = new Connector(attributes.getValue("protocol"));
     9	        if ( ex != null )  _setExecutor(con,ex);
    10	        
    11	        digester.push(con);
    12	    }

在第 8 行,会根据配置文件中 Server/Service/Connector 节点的 protocol 属性调用 org.apache.catalina.connector.Connector 类的构造方法,而默认情况下 server.xml 文件中 Server/Service/Connector 节点共有两处配置:

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

先看第一个 Connector 节点,调用 Connector 的构造方法时会传入字符串 HTTP/1.1

     1	    public Connector(String protocol) {
     2	        setProtocol(protocol);
     3	        // Instantiate protocol handler
     4	        try {
     5	            Class<?> clazz = Class.forName(protocolHandlerClassName);
     6	            this.protocolHandler = (ProtocolHandler) clazz.newInstance();
     7	        } catch (Exception e) {
     8	            log.error(sm.getString(
     9	                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
    10	        }
    11	    }

这里先会执行 org.apache.catalina.connector.Connector 类的 setProtocol 方法:

     1	    public void setProtocol(String protocol) {
     2	
     3	        if (AprLifecycleListener.isAprAvailable()) {
     4	            if ("HTTP/1.1".equals(protocol)) {
     5	                setProtocolHandlerClassName
     6	                    ("org.apache.coyote.http11.Http11AprProtocol");
     7	            } else if ("AJP/1.3".equals(protocol)) {
     8	                setProtocolHandlerClassName
     9	                    ("org.apache.coyote.ajp.AjpAprProtocol");
    10	            } else if (protocol != null) {
    11	                setProtocolHandlerClassName(protocol);
    12	            } else {
    13	                setProtocolHandlerClassName
    14	                    ("org.apache.coyote.http11.Http11AprProtocol");
    15	            }
    16	        } else {
    17	            if ("HTTP/1.1".equals(protocol)) {
    18	                setProtocolHandlerClassName
    19	                    ("org.apache.coyote.http11.Http11Protocol");
    20	            } else if ("AJP/1.3".equals(protocol)) {
    21	                setProtocolHandlerClassName
    22	                    ("org.apache.coyote.ajp.AjpProtocol");
    23	            } else if (protocol != null) {
    24	                setProtocolHandlerClassName(protocol);
    25	            }
    26	        }
    27	
    28	    }

所以此时会调用 setProtocolHandlerClassName("org.apache.coyote.http11.Http11Protocol") 从而将 Connector 类实例变量 protocolHandlerClassName 值设置为 org.apache.coyote.http11.Http11Protocol ,接下来在 Connector 的构造方法中就会根据 protocolHandlerClassName 变量的值产生一个 org.apache.coyote.http11.Http11Protocol 对象,并将该对象赋值给 Connector 类的实例变量 protocolHandler 。在 Http11Protocol 类的构造方法中会产生一个 org.apache.tomcat.util.net.JIoEndpoint 对象:







请到「今天看啥」查看全文