Tomcat系统架构分析

1.  Connector 组件

Connector 组件是 Tomcat 中两个核心组件之一,它的主要任务是负责接收浏览器的发过来的 tcp 连接请求,创建一个 Request 和 Response 对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的 Request 和 Response 对象传给处理这个请求的线程,处理这个请求的线程就是 Container 组件要做的事了。

由于这个过程比较复杂,大体的流程可以用下面的顺序图来解释:

1.1. Connector 处理一次请求顺序图

Tomcat5 中默认的 Connector 是 Coyote,这个 Connector 是可以选择替换的。Connector 最重要的功能就是接收连接请求然后分配线程让 Container 来处理这个请求,所以这必然是多线程的,多线程的处理是 Connector 设计的核心。Tomcat5 将这个过程更加细化,它将 Connector 划分成 Connector、Processor、Protocol, 另外 Coyote 也定义自己的 Request 和 Response 对象。

下面主要看一下 Tomcat 中如何处理多线程的连接请求,先看一下 Connector 的主要类图:

1.1. Connector 的主要类图

 

看一下 HttpConnector 的 Start 方法:

1.1. HttpConnector.Start

public void start() throws LifecycleException {

    if (started)

        throw new LifecycleException

            (sm.getString("httpConnector.alreadyStarted"));

    threadName = "HttpConnector[" + port + "]";

    lifecycle.fireLifecycleEvent(START_EVENT, null);

    started = true;

    threadStart();

    while (curProcessors < minProcessors) {

        if ((maxProcessors > 0) && (curProcessors >= maxProcessors))

            break;

        HttpProcessor processor = newProcessor();

        recycle(processor);

    }

}

threadStart() 执行就会进入等待请求的状态,直到一个新的请求到来才会激活它继续执行,这个激活是在 HttpProcessor 的 assign 方法中,这个方法是代码如下 :

1.2. HttpProcessor.assign

synchronized void assign(Socket socket) {

    while (available) {

        try {

            wait();

        } catch (InterruptedException e) {

        }

    }

    this.socket = socket;

    available = true;

    notifyAll();

    if ((debug >= 1) && (socket != null))

        log(" An incoming request is being assigned");

}

创建 HttpProcessor 对象是会把 available 设为 false,所以当请求到来时不会进入 while 循环,将请求的 socket 赋给当期处理的 socket,并将 available 设为 true,当 available 设为 true 是 HttpProcessor 的 run 方法将被激活,接下去将会处理这次请求。

Run 方法代码如下:

1.3. HttpProcessor.Run

public void run() {

    while (!stopped) {

        Socket socket = await();

        if (socket == null)

            continue;

        try {

            process(socket);

        } catch (Throwable t) {

            log("process.invoke", t);

        }

        connector.recycle(this);

    }

    synchronized (threadSync) {

        threadSync.notifyAll();

    }

}

解析 socket 的过程在 process 方法中,process 方法的代码片段如下:

 

1.1. HttpProcessor.process

 private void process(Socket socket) {

    boolean ok = true;

    boolean finishResponse = true;

    SocketInputStream input = null;

    OutputStream output = null;

    try {

        input = new SocketInputStream(socket.getInputStream(),connector.getBufferSize());

    } catch (Exception e) {

        log("process.create", e);

        ok = false;

    }

    keepAlive = true;

    while (!stopped && ok && keepAlive) {

        finishResponse = true;

        try {

            request.setStream(input);

            request.setResponse(response);

            output = socket.getOutputStream();

            response.setStream(output);

            response.setRequest(request);

            ((HttpServletResponse) response.getResponse())

.setHeader("Server", SERVER_INFO);

        } catch (Exception e) {

            log("process.create", e);

            ok = false;

        }

        try {

            if (ok) {

                parseConnection(socket);

                parseRequest(input, output);

                if (!request.getRequest().getProtocol().startsWith("HTTP/0"))

                    parseHeaders(input);

                if (http11) {

                    ackRequest(output);

                    if (connector.isChunkingAllowed())

                        response.setAllowChunking(true);

                }

            }

        。。。。。。

        try {

            ((HttpServletResponse) response).setHeader

                ("Date", FastHttpDateFormat.getCurrentDate());

            if (ok) {

                connector.getContainer().invoke(request, response);

            }

            。。。。。。

        }

        try {

            shutdownInput(input);

            socket.close();

        } catch (IOException e) {

            ;

        } catch (Throwable e) {

            log("process.invoke", e);

        }

    socket = null;

}

当 Connector 将 socket 连接封装成 request 和 response 对象后接下来的事情就交给 Container 来处理了。

 

回页首

 

本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源,欢迎大家关注尚硅谷公众号(atguigu)了解更多。