Tomcat異步分析

tomcat長(zhǎng)連接使用

新建AsyncContext 圾旨,然后將AsyncContext 放入到線程池中執(zhí)行。

        AsyncContext asyncContext = request.startAsync();
        asyncContext.addListener(new AppAsyncListener());
        asyncContext.setTimeout(timeout);
        ThreadPoolExecutor executor = (ThreadPoolExecutor) request
                .getServletContext().getAttribute("executor");
        executor.execute(new AsyncRequestProcessor(asyncContext, workTime));

啟動(dòng)分析

image.png

1 獲取AsyncContext

org.apache.catalina.connector.Request#startAsync()

    public AsyncContext startAsync(ServletRequest request,
            ServletResponse response) {
        if (!isAsyncSupported()) {
            throw new IllegalStateException(sm.getString("request.asyncNotSupported"));
        }
        if (asyncContext == null) {
// 新建asyncContext 
            asyncContext = new AsyncContextImpl(this);
        }
//設(shè)置啟動(dòng)狀態(tài)
        asyncContext.setStarted(getContext(), request, response,
                request==getRequest() && response==getResponse().getResponse());
// 設(shè)置默認(rèn)超時(shí)時(shí)間
        asyncContext.setTimeout(getConnector().getAsyncTimeout());
        return asyncContext;
    }

org.apache.catalina.core.AsyncContextImpl#setStarted

 public void setStarted(Context context, ServletRequest request,
            ServletResponse response, boolean originalRequestResponse) {

        synchronized (asyncContextLock) {
// 重點(diǎn)關(guān)注
            this.request.getCoyoteRequest().action(
                    ActionCode.ASYNC_START, this);

            this.context = context;
            this.servletRequest = request;
            this.servletResponse = response;
            this.hasOriginalRequestAndResponse = originalRequestResponse;
            this.event = new AsyncEvent(this, request, response);

// 觸發(fā)注冊(cè)的Listener
            List<AsyncListenerWrapper> listenersCopy = new ArrayList<>();
            listenersCopy.addAll(listeners);
            listeners.clear();
            for (AsyncListenerWrapper listener : listenersCopy) {
                try {
                    listener.fireOnStartAsync(event);
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.warn("onStartAsync() failed for listener of type [" +
                            listener.getClass().getName() + "]", t);
                }
            }
        }
    }

設(shè)置異步狀態(tài)
org.apache.coyote.http11.Http11Processor#action 845行

// 異步啟動(dòng)
        case ASYNC_START: {
//設(shè)置異步狀態(tài)為STARTING
            asyncStateMachine.asyncStart((AsyncContextCallback) param);
            break;
        }
// 異步完成峭梳,這個(gè)稍后會(huì)用到
        case ASYNC_COMPLETE: {
            clearDispatches();
            if (asyncStateMachine.asyncComplete()) {
                socketWrapper.processSocket(SocketEvent.OPEN_READ, true);
            }
            break;
        }

任務(wù)提交后的后續(xù)處理

image.png

從Valve及FilterChain返回后,進(jìn)入org.apache.catalina.connector.CoyoteAdapter#service蹂喻。它最主要作用是不關(guān)閉request和response葱椭。

if (postParseSuccess) {
                //check valves if we support async
           request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
                // Calling the container 去調(diào)用Servlet
                connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
            }
//設(shè)置異步
            if (request.isAsync()) {
                async = true;
.....
     } else {
                request.finishRequest();
                response.finishResponse();
            }

從CoyoteAdapter返回到Http11Processor
org.apache.coyote.http11.Http11Processor#service

   if (getErrorState().isError() || endpoint.isPaused()) {
            return SocketState.CLOSED;
        } else if (isAsync()) {
// 返回值
            return SocketState.LONG;
        } else if (isUpgrade()) {
            return SocketState.UPGRADING;
        } else {

org.apache.coyote.AbstractProtocol.ConnectionHandler#process

 if (state == SocketState.LONG) {
                    // In the middle of processing a request/response. Keep the
                    // socket associated with the processor. Exact requirements
                    // depend on type of long poll
                    longPoll(wrapper, processor);
// 將Processor加入到等待處理隊(duì)列
                    if (processor.isAsync()) {
                        getProtocol().addWaitingProcessor(processor);
                    }
                } 

任務(wù)完成

任務(wù)完成時(shí)需要主動(dòng)調(diào)用

        asyncContext.complete();

org.apache.catalina.core.AsyncContextImpl#complete

    public void complete() {
        if (log.isDebugEnabled()) {
            logDebug("complete   ");
        }
        check();
//這個(gè)和啟動(dòng)的時(shí)候類似
        request.getCoyoteRequest().action(ActionCode.ASYNC_COMPLETE, null);
    }

action觸發(fā)socketWrapper.processSocket(SocketEvent.OPEN_READ, true);

org.apache.tomcat.util.net.AbstractEndpoint#processSocket
觸發(fā)processor處理請(qǐng)求

 public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {
        try {
            if (socketWrapper == null) {
                return false;
            }
            SocketProcessorBase<S> sc = processorCache.pop();
            if (sc == null) {
                sc = createSocketProcessor(socketWrapper, event);
            } else {
                sc.reset(socketWrapper, event);
            }
            Executor executor = getExecutor();
            if (dispatch && executor != null) {
                executor.execute(sc);
            } else {
                sc.run();
            }
        } 

超時(shí)處理

超時(shí)處理線程

org.apache.coyote.AbstractProtocol.AsyncTimeout

 while (asyncTimeoutRunning) {
// 每隔一秒掃描一次
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
                long now = System.currentTimeMillis();
// 從waitingProcessors去除Processor
                for (Processor processor : waitingProcessors) {
                   processor.timeoutAsync(now);
                }
                while (endpoint.isPaused() && asyncTimeoutRunning) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
            }

addWaitingProcessor來(lái)源

org.apache.coyote.AbstractProtocol#addWaitingProcessor

// 在servlet返回中調(diào)用的
public void addWaitingProcessor(Processor processor) {
        waitingProcessors.add(processor);
    }

判斷是否超時(shí)

org.apache.coyote.AbstractProcessor#timeoutAsync

    public void timeoutAsync(long now) {
        if (now < 0) {
            doTimeoutAsync();
        } else {
            long asyncTimeout = getAsyncTimeout();
            if (asyncTimeout > 0) {
                long asyncStart = asyncStateMachine.getLastAsyncStart();
                if ((now - asyncStart) > asyncTimeout) {
        //觸發(fā)超時(shí)處理变勇,可以在這一行打斷點(diǎn)
                    doTimeoutAsync();
                }
            }
        }
    }

參考

https://zhuanlan.zhihu.com/p/22018499
http://www.importnew.com/8864.html
http://blog.csdn.net/wangyangzhizhou/article/details/53207966

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末做粤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子惠呼,更是在濱河造成了極大的恐慌蔓彩,老刑警劉巖治笨,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異赤嚼,居然都是意外死亡旷赖,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)更卒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)等孵,“玉大人,你說(shuō)我怎么就攤上這事蹂空「┟龋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵上枕,是天一觀的道長(zhǎng)绳瘟。 經(jīng)常有香客問(wèn)我,道長(zhǎng)姿骏,這世上最難降的妖魔是什么糖声? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上蘸泻,老公的妹妹穿的比我還像新娘琉苇。我一直安慰自己,他們只是感情好悦施,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布并扇。 她就那樣靜靜地躺著,像睡著了一般抡诞。 火紅的嫁衣襯著肌膚如雪穷蛹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天昼汗,我揣著相機(jī)與錄音肴熏,去河邊找鬼。 笑死顷窒,一個(gè)胖子當(dāng)著我的面吹牛蛙吏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鞋吉,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸦做,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了谓着?” 一聲冷哼從身側(cè)響起泼诱,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赊锚,沒(méi)想到半個(gè)月后治筒,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡改抡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年矢炼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了系瓢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阿纤。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夷陋,靈堂內(nèi)的尸體忽然破棺而出欠拾,到底是詐尸還是另有隱情,我是刑警寧澤骗绕,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布藐窄,位于F島的核電站,受9級(jí)特大地震影響酬土,放射性物質(zhì)發(fā)生泄漏荆忍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刹枉。 院中可真熱鬧叽唱,春花似錦、人聲如沸微宝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蟋软。三九已至镶摘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岳守,已是汗流浹背凄敢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棺耍,地道東北人贡未。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蒙袍,于是被迫代替她去往敵國(guó)和親俊卤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容