`
liudeh_009
  • 浏览: 242741 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

解析Tomcat处理请求的类Connector<三>

阅读更多

      这次主要解析采用apr方式处理请求.apr用C实现,通过JNI调用,主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能.在tomcat下配置apr步骤:

  1.下载本地库tcnative-1.dll,放在%jdk%\bin目录下(见附件).

  2.在server.xml里配置listener,这个配置server.xml默认是有的

     

  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />

 

  3.在server.xml里配置apr connector

  

     <Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol" 
               connectionTimeout="20000" 
               redirectPort="8443" />

 

    在tomcat启动的时候,会调用Connector类的Start()方法,根据以上配置,Connector的start()方法里会调用Http11AprProtocol类的start()方法,如下:

  

       try {
            protocolHandler.start();
        } catch (Exception e) {
            String errPrefix = "";
            if(this.service != null) {
                errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
            }

            throw new LifecycleException
                (errPrefix + " " + sm.getString
                 ("coyoteConnector.protocolHandlerStartFailed", e));
        }

 

   

   Http11AprProtocol类的start()方法又会调用AprEndpoint类的start()方法,如下:

     try {
            endpoint.start();
        } catch (Exception ex) {
            log.error(sm.getString("http11protocol.endpoint.starterror"), ex);
            throw ex;
        }

    AprEndpoint类的start()方法如下:

public void start()
        throws Exception {
        // Initialize socket if not done before
        if (!initialized) {
            init();
        }
        if (!running) {
            running = true;
            paused = false;

            // Create worker collection
            if (executor == null) {
                workers = new WorkerStack(maxThreads);
            }

            // Start poller threads
            pollers = new Poller[pollerThreadCount];
            for (int i = 0; i < pollerThreadCount; i++) {
                pollers[i] = new Poller(false);
                pollers[i].init();
                pollers[i].setName(getName() + "-Poller-" + i);
                pollers[i].setPriority(threadPriority);
                pollers[i].setDaemon(true);
                pollers[i].start();
            }

            // Start comet poller threads
            cometPollers = new Poller[pollerThreadCount];
            for (int i = 0; i < pollerThreadCount; i++) {
                cometPollers[i] = new Poller(true);
                cometPollers[i].init();
                cometPollers[i].setName(getName() + "-CometPoller-" + i);
                cometPollers[i].setPriority(threadPriority);
                cometPollers[i].setDaemon(true);
                cometPollers[i].start();
            }

            // Start sendfile threads
            if (useSendfile) {
                sendfiles = new Sendfile[sendfileThreadCount];
                for (int i = 0; i < sendfileThreadCount; i++) {
                    sendfiles[i] = new Sendfile();
                    sendfiles[i].init();
                    sendfiles[i].setName(getName() + "-Sendfile-" + i);
                    sendfiles[i].setPriority(threadPriority);
                    sendfiles[i].setDaemon(true);
                    sendfiles[i].start();
                }
            }

            // Start acceptor threads
            acceptors = new Acceptor[acceptorThreadCount];
            for (int i = 0; i < acceptorThreadCount; i++) {
                acceptors[i] = new Acceptor();
                acceptors[i].setName(getName() + "-Acceptor-" + i);
                acceptors[i].setPriority(threadPriority);
                acceptors[i].setDaemon(getDaemon());
                acceptors[i].start();
            }

        }
    }

        该方法主要初始化接受socket的线程和处理socket的线程池.Acceptor的run()方法如下:

   

public void run() {

            // Loop until we receive a shutdown command
            while (running) {

                // Loop if endpoint is paused
                while (paused && running) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                if (!running) {
                    break;
                }
                try {
                    // Accept the next incoming connection from the server socket
                    long socket = Socket.accept(serverSock);
                    /*
                     * In the case of a deferred accept unlockAccept needs to
                     * send data. This data will be rubbish, so destroy the
                     * socket and don't process it.
                     */
                    if (deferAccept && (paused || !running)) {
                        destroySocket(socket);
                        continue;
                    }
                    // Hand this socket off to an appropriate processor
                    if (!processSocketWithOptions(socket)) {//把socket交给woker线程进行转发
                        // Close socket and pool right away
                        destroySocket(socket);
                    }
                } catch (Throwable t) {
                    if (running) {
                        String msg = sm.getString("endpoint.accept.fail");
                        if (t instanceof Error) {
                            Error e = (Error) t;
                            if (e.getError() == 233) {
                                // Not an error on HP-UX so log as a warning
                                // so it can be filtered out on that platform
                                // See bug 50273
                                log.warn(msg, t);
                            } else {
                                log.error(msg, t);
                            }
                        } else {
                                log.error(msg, t);
                        }
                    }
                }

            }

        }

    }

 

   Socket.accept(serverSock)方法的Socket类是用JNI实现的不同于java的Socket类,所以 Socket.accept(serverSock)返回的参数是long类型的.processSocketWithOptions(socket)方法如下:

    

    protected boolean processSocketWithOptions(long socket) {
        try {
            if (executor == null) {
                getWorkerThread().assignWithOptions(socket);
            } else {
                executor.execute(new SocketWithOptionsProcessor(socket));
            }
        } catch (Throwable t) {
            // This means we got an OOM or similar creating a thread, or that
            // the pool and its queue are full
            log.error(sm.getString("endpoint.process.fail"), t);
            return false;
        }
        return true;
    }

 

   再来看一下woker线程的run方法():

  

public void run() {

            // Process requests until we receive a shutdown signal
            while (running) {

                // Wait for the next socket to be assigned
                long socket = await();
                if (socket == 0)
                    continue;

                if (!deferAccept && options) {
                    if (setSocketOptions(socket)) {
                        getPoller().add(socket);//将sokcet交给poller转发.poller最终会把socket交给worker处理不知道为什么这么做
                    } else {
                        // Close socket and pool
                        destroySocket(socket);
                        socket = 0;
                    }
                } else {

                    // Process the request from this socket
                    if ((status != null) && (handler.event(socket, status) == Handler.SocketState.CLOSED)) {
                        // Close socket and pool
                        destroySocket(socket);
                        socket = 0;
                    } else if ((status == null) && ((options && !setSocketOptions(socket))
                            || handler.process(socket) == Handler.SocketState.CLOSED)) {//Http11AprProtocol.Http11ConnectionHandler.process(socket)处理socket
                        // Close socket and pool
                        destroySocket(socket);
                        socket = 0;
                    }
                }

                // Finish up this request
                recycleWorkerThread(this);

            }

        }

 

可以看到,woker的run()方法做了两件事.1.把socket交给poller.2.直接调用处理 Http11AprProtocol.Http11ConnectionHandler.process(socket)处理socket

 handler.process(socket)方法如下:    

 public SocketState process(long socket) {
            Http11AprProcessor processor = recycledProcessors.poll();
            try {
                if (processor == null) {
                    processor = createProcessor();
                }

                if (processor instanceof ActionHook) {
                    ((ActionHook) processor).action(ActionCode.ACTION_START, null);
                }

                SocketState state = processor.process(socket);//真正的解析http请求的方法
                if (state == SocketState.LONG) {//如果是长连接再放回线程池处理
                    // Associate the connection with the processor. The next request 
                    // processed by this thread will use either a new or a recycled
                    // processor.
                    connections.put(socket, processor);
                    proto.endpoint.getCometPoller().add(socket);
                } else {
                    recycledProcessors.offer(processor);
                }
                return state;

            } catch (java.net.SocketException e) {
                // SocketExceptions are normal
                Http11AprProtocol.log.debug
                    (sm.getString
                     ("http11protocol.proto.socketexception.debug"), e);
            } catch (java.io.IOException e) {
                // IOExceptions are normal
                Http11AprProtocol.log.debug
                    (sm.getString
                     ("http11protocol.proto.ioexception.debug"), e);
            }
            // Future developers: if you discover any other
            // rare-but-nonfatal exceptions, catch them here, and log as
            // above.
            catch (Throwable e) {
                // any other exception or error is odd. Here we log it
                // with "ERROR" level, so it will show up even on
                // less-than-verbose logs.
                Http11AprProtocol.log.error
                    (sm.getString("http11protocol.proto.error"), e);
            }
            recycledProcessors.offer(processor);
            return SocketState.CLOSED;
        }

     processor.process(socket)调用的是Http11AprProcessor类的process(long socket) 方法,用http协议对http请求进行解析

0
0
分享到:
评论

相关推荐

    tomcat概述和体系架构

    在结构上,Tomcat的顶层类元素包括`&lt;Server&gt;`和`&lt;Service&gt;`,连接器类元素负责通信接口,而容器类元素则分为`Engine`、`Host`和`Context`,它们分别负责处理请求、特定虚拟主机请求和特定Web应用请求。所有的Tomcat...

    Tomcat 配置详解

    本文将详细解析Tomcat的核心配置元素,包括`&lt;Server&gt;`、`&lt;Service&gt;`、`&lt;Engine&gt;`、`&lt;Host&gt;`和`&lt;Context&gt;`,帮助读者更好地理解和优化Tomcat的运行环境。 首先,`&lt;Server&gt;`元素是Tomcat实例的顶级容器,由`org....

    ssm黑马旅游整合最终版2018

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;/dependency&gt; &lt;!-- 日志 --&gt; &lt;dependency&gt; &lt;groupId&gt;org.slf4j&lt;/groupId&gt; &lt;artifactId&gt;slf4j-log4j12&lt;/artifactId&gt; &lt;/dependency&gt; &lt;!-- 连接池 --&gt; ...

    Tomcat的server.xml文件

    4. `&lt;Engine&gt;`元素:`&lt;Engine&gt;`代表一个Servlet引擎,处理来自`&lt;Connector&gt;`的所有请求。`name`属性是引擎的名称,通常默认为`Catalina`。它还可以包含一个或多个`&lt;Host&gt;`元素,每个`&lt;Host&gt;`代表虚拟主机。 5. `...

    tomcat服务器的配置详解

    3. **WEB SERVICE部分**:这部分由`&lt;Service&gt;`标签表示,定义了Tomcat的服务实例,每个服务可以包含多个`&lt;Connector&gt;`(监听端口)和`&lt;Engine&gt;`(处理HTTP请求)。`&lt;Connector&gt;`配置了Tomcat监听的IP地址和端口,...

    Tomcat解析与性能优化.pdf

    - `&lt;Service&gt;` 元素:每个 `&lt;Service&gt;` 元素只能有一个 `&lt;Engine&gt;` 元素,处理所有 `&lt;Connector&gt;` 元素接收到的客户请求。 - `&lt;Engine&gt;` 元素:处理在同一 `&lt;Service&gt;` 中所有 `&lt;Connector&gt;` 元素接收到的客户请求...

    Tomcat的配置文件server.xml中各个域的说明及相关配置.pdf

    `&lt;Service&gt;`通常用于处理来自Web客户端的请求,而`&lt;Connector&gt;`元素则负责连接器的配置,用于定义如何与客户端进行通信。 接着,`&lt;Engine&gt;`元素是`&lt;Service&gt;`的子元素,由`org.apache.catalina.Engine`接口定义,它...

    tomcat_server.xml_配置详解

    `&lt;Engine&gt;`是Service的服务引擎,它负责接收和处理来自Connector的所有请求。`defaultHost`属性定义了默认处理请求的主机名。 5. `&lt;Host&gt;`元素 `&lt;Host&gt;`元素代表一个虚拟主机,它有自己的名称(`name`属性)和...

    tomcat结构分析

    `&lt;Service&gt;`元素不直接处理请求,它是一个或多个`&lt;Connector&gt;`和一个`&lt;Engine&gt;`的集合。每个`&lt;Service&gt;`都关联一个特定的`&lt;Engine&gt;`,用于处理所有传入的请求。 3. **Connector 组件** `&lt;Connector&gt;`组件是Tomcat...

    tomcat server.xml元素详细说明

    `&lt;Engine&gt;`元素是处理来自`&lt;Connector&gt;`请求的容器。它拥有`defaultHost`属性,指定默认处理请求的虚拟主机名称。 ### 5. &lt;Host&gt; 元素:虚拟主机 `&lt;Host&gt;`元素用于配置虚拟主机,每个`&lt;Host&gt;`元素代表一个虚拟主机...

    一个详细介绍tomcat6.0的内部结构的文档

    - `&lt;Engine&gt;` 元素是 `&lt;Service&gt;` 的子元素,它代表了 Tomcat 的“引擎”,负责处理 `&lt;Connector&gt;` 接收到的请求。 - `&lt;Engine&gt;` 组件可以包含一个或多个 `&lt;Host&gt;` 元素,每个 `&lt;Host&gt;` 对应一个虚拟主机。 5. **...

    server.xml常用配置详解.docx

    每个 `&lt;Service&gt;` 只能包含一个 `&lt;Engine&gt;`,用于处理在同一 `&lt;Service&gt;` 中的所有 `&lt;Connector&gt;` 接收到的客户端请求,并将处理结果返回给 `&lt;Connector&gt;`。 - **支持的属性**:`&lt;Engine&gt;` 元素通常不会直接配置...

    Tomcat完整教程

    - `&lt;Engine&gt;`:容器类元素,处理特定Service的所有请求,可以包含多个`&lt;Host&gt;`。 - `&lt;Host&gt;`:处理特定虚拟主机的请求,可以包含多个`&lt;Context&gt;`。 - `&lt;Context&gt;`:处理特定Web应用的请求,是最底层的容器。 5. ...

    SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;5.1.37&lt;/version&gt; &lt;/dependency&gt; &lt;!-- 日志相关 --&gt; &lt;dependency&gt; &lt;groupId&gt;log4j&lt;/groupId&gt; &lt;artifactId&gt;log4j&lt;/artifactId&gt; &lt;version&gt;${log4j....

    tomcat_server.xml_配置详解.doc

    `&lt;Engine&gt;`元素表示一个请求处理机,负责接收和处理来自`&lt;Connector&gt;`的请求。关键配置包括: - **defaultHost**:指定默认处理请求的主机名,需与某`&lt;Host&gt;`元素的`name`属性匹配。 ### 5. &lt;Host&gt; 元素:虚拟主机...

    TOMCAT技术介绍.docx

    每个&lt;Service&gt;元素包含一个&lt;Connector&gt;,用于监听和处理网络连接,一个&lt;Engine&gt;用于处理特定Service的所有客户请求,以及多个&lt;Host&gt;,每个&lt;Host&gt;代表一个虚拟主机,可以包含多个&lt;Context&gt;,每个&lt;Context&gt;对应一个Web...

    基于IDEA的ssm(spring+springMVC+mybatis)基本框架

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;8.x.x&lt;/version&gt; &lt;/dependency&gt; &lt;!-- Servlet & JSTL for view rendering --&gt; &lt;dependency&gt; &lt;groupId&gt;javax.servlet&lt;/groupId&gt; &lt;artifactId&gt;javax....

    tomcat-server.xml详解

    `&lt;Engine&gt;`元素是请求处理引擎,负责接收来自`Connector`的请求并分发给相应的`Host`。`defaultHost`属性指定了未明确指定主机名时的默认处理主机。`&lt;Host&gt;`元素代表虚拟主机,`name`属性定义了主机名,`appBase`...

    Spring+SpringMVC+Mybatis框架整合例子

    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt; &lt;version&gt;8.x.y.RELEASE&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt; ``` 接下来,配置Spring的核心文件ApplicationContext.xml,包括Bean的定义和AOP、DI的配置。...

Global site tag (gtag.js) - Google Analytics