千家信息网

Tomcat处理请求的线程模型是什么

发表于:2024-09-25 作者:千家信息网编辑
千家信息网最后更新 2024年09月25日,小编给大家分享一下Tomcat处理请求的线程模型是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、前言JAVA后端项
千家信息网最后更新 2024年09月25日Tomcat处理请求的线程模型是什么

小编给大家分享一下Tomcat处理请求的线程模型是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

    一、前言

    JAVA后端项目,运行在容器tomcat中,由于现在springboot的内置tomcat容器,其默认配置屏蔽了很多对tomcat的认知,但是对tomcat的学习和认识是比较重要的,所以专门查资料加深了理解,本文主要讨论在springboot集成下的tomcat9的请求过程,线程模型为NIO。

    二、tomcat结构

    找了张结构图,每个模块的意思和作用就不详解了,可以搜其他文章

    三、探讨tomcat是如何处理请求

    自己画了一个connector的结构

    1、初始化

    在springboot启动后,org.springframework.context.support.AbstractApplicationContext#finishRefresh,这里进去调用org.springframework.boot.web.servlet.context.WebServerStartStopLifecycle.start()方法启动TomcatWebServer,初始化tomcat。

    通过这样的调用链到达org.apache.tomcat.util.net.NioEndpoint#startInternal(),进行初始化Endpoint中的AcceptorPoller,这两者都实现了Runnable接口,初始化后就通过线程start启动了。

    2、如何处理客户端请求

    Acceptor: 接收器,作用是接受scoket网络请求,并调用setSocketOptions()封装成为NioSocketWrapper,并注册到Poller的events中。注意查看run方法org.apache.tomcat.util.net.Acceptor#run

     @Override    public void run() {        int errorDelay = 0;        try {            // Loop until we receive a shutdown command            while (!stopCalled) {                // Loop if endpoint is paused                while (endpoint.isPaused() && !stopCalled) {                    state = AcceptorState.PAUSED;                    try {                        Thread.sleep(50);                    } catch (InterruptedException e) {                        // Ignore                    }                }                if (stopCalled) {                    break;                }                state = AcceptorState.RUNNING;                try {                    //if we have reached max connections, wait                    endpoint.countUpOrAwaitConnection();                    // Endpoint might have been paused while waiting for latch                    // If that is the case, don't accept new connections                    if (endpoint.isPaused()) {                        continue;                    }                    U socket = null;                    try {                        // 等待下一个请求进来                        socket = endpoint.serverSocketAccept();                    } catch (Exception ioe) {                        // We didn't get a socket                        endpoint.countDownConnection();                        if (endpoint.isRunning()) {                            // Introduce delay if necessary                            errorDelay = handleExceptionWithDelay(errorDelay);                            // re-throw                            throw ioe;                        } else {                            break;                        }                    }                    // Successful accept, reset the error delay                    errorDelay = 0;                    // Configure the socket                    if (!stopCalled && !endpoint.isPaused()) {                        // 注册socket到Poller,生成PollerEvent事件                        if (!endpoint.setSocketOptions(socket)) {                            endpoint.closeSocket(socket);                        }                    } else {                        endpoint.destroySocket(socket);                    }                } catch (Throwable t) {                    ExceptionUtils.handleThrowable(t);                    String msg = sm.getString("endpoint.accept.fail");                    // APR specific.                    // Could push this down but not sure it is worth the trouble.                    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);                    }                }            }        } finally {            stopLatch.countDown();        }        state = AcceptorState.ENDED;    }

    Poller:轮询器,轮询是否有事件达到,有请求事件到达后,以NIO的处理方式,查询Selector取出所有请求,遍历每个请求的需求,分配给Executor线程池执行。查看org.apache.tomcat.util.net.NioEndpoint.Poller#run()

     public void run() {            // Loop until destroy() is called            while (true) {                boolean hasEvents = false;                try {                    if (!close) {                        hasEvents = events();                        if (wakeupCounter.getAndSet(-1) > 0) {                            // If we are here, means we have other stuff to do                            // Do a non blocking select                            keyCount = selector.selectNow();                        } else {                            keyCount = selector.select(selectorTimeout);                        }                        wakeupCounter.set(0);                    }                    if (close) {                        events();                        timeout(0, false);                        try {                            selector.close();                        } catch (IOException ioe) {                            log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);                        }                        break;                    }                    // Either we timed out or we woke up, process events first                    if (keyCount == 0) {                        hasEvents = (hasEvents | events());                    }                } catch (Throwable x) {                    ExceptionUtils.handleThrowable(x);                    log.error(sm.getString("endpoint.nio.selectorLoopError"), x);                    continue;                }                                //查询selector取出所有请求                Iterator iterator =                    keyCount > 0 ? selector.selectedKeys().iterator() : null;                // Walk through the collection of ready keys and dispatch                // any active event.                while (iterator != null && iterator.hasNext()) {                    SelectionKey sk = iterator.next();                    iterator.remove();                    NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();                    //处理请求key                    if (socketWrapper != null) {                        processKey(sk, socketWrapper);                    }                }                // Process timeouts                timeout(keyCount,hasEvents);            }            getStopLatch().countDown();        }

    请求过程大致如下图:

    以上是"Tomcat处理请求的线程模型是什么"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

    0