温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2022-03-25 09:17:17 来源:亿速云 阅读:135 作者:小新 栏目:开发技术

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

    一、前言

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

    二、tomcat结构

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

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

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

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

    自己画了一个connector的结构

    1、初始化

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

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

    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<SelectionKey> 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处理请求的线程模型是什么

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

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI