千家信息网

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

发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,小编给大家分享一下Tomcat处理请求的线程模型是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、前言JAVA后端项
千家信息网最后更新 2025年01月31日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处理请求的线程模型是什么"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

    线程 处理 模型 事件 篇文章 结构 作用 内容 容器 方法 过程 学习 查询 重要 不怎么 前言 大部分 客户 客户端 意思 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 数据库课程设计团队心得体会 面试数据库优化题 文件存放位置不是共享服务器 网络安全宣传8k画 计算机网络安全的概况 嵌入式系统软件开发需要什么知识 济南数据库监控 江苏网络技术价目表 专业 app 软件开发 数据库系统概论期中考试题库 数据库安装完怎么知道账号密码 财务管理软件开发服务采购 兰州鲲鹏服务器供应商 澳门软件开发实惠 网络安全与社会治理论坛 服务器显示未连接无法上网 大疆软件开发笔试选择题 软件开发人员 会计分录 使用云平台系统和数据库安全 网络安全方面整改措施 汕尾数据链软件开发供应商 桃花源记全部服务器 高中学历学软件开发好就业吗 数码喷泉控制软件开发 咪咕互娱软件开发支撑项目 网络安全技术课后练习题 网络安全知识答题2021河北 数据库统计功能是什么功能 使用云平台系统和数据库安全 开展网络安全培训的效果
    0