中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

    广昌县| 肃宁县| 成安县| 菏泽市| 高陵县| 江津市| 新干县| 大厂| 北流市| 哈尔滨市| 四平市| 三台县| 庆安县| 六盘水市| 利辛县| 禄丰县| 双辽市| 汝城县| 绥滨县| 乐平市| 拜泉县| 宜丰县| 新泰市| 兴山县| 邹平县| 四川省| 平潭县| 滨海县| 隆林| 两当县| 隆安县| 合肥市| 长汀县| 视频| 敦煌市| 竹溪县| 温州市| 云林县| 桃江县| 奈曼旗| 通城县|