<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          給你講明白啥是SpringMvc異步處理

          共 4527字,需瀏覽 10分鐘

           ·

          2020-01-01 23:22


          本文公眾號(hào)來(lái)源:編程新說(shuō)作者:編程新說(shuō)李新杰本文已收錄至我的GitHub


          生活在這個(gè)世界上,我們必須承認(rèn)任何事物都是運(yùn)動(dòng)變化著的,沒(méi)有什么東西是一成不變的。

          不僅因?yàn)檫@句話是出自馬克思主義哲學(xué)的唯物辯證法,而且事實(shí)確實(shí)如此。下面就來(lái)描述這樣的一個(gè)變化。


          分工的產(chǎn)生與協(xié)作


          想必大家都買(mǎi)過(guò)房或終將會(huì)買(mǎi)房,那自然離不開(kāi)裝修,就以裝修這個(gè)話題來(lái)展開(kāi)吧。假設(shè)有一個(gè)搞裝修的人叫小王。

          小王活兒做得特別好,但目前還是一個(gè)人單打獨(dú)斗。他正在干活兒的這家業(yè)主的鄰居發(fā)現(xiàn)了他的活兒好,于是專門(mén)來(lái)找他咨詢情況。

          小王不得不停下手頭的工作,來(lái)為潛在的客戶解答疑惑或訴說(shuō)方案。最終靠實(shí)力把潛在客戶變成了真正的客戶。小王的名氣就這樣傳開(kāi)了。

          附近小區(qū)的人聞名而來(lái),找他溝通裝修方案或確認(rèn)時(shí)間安排,小王不得不每次都停下手頭工作,專心為客戶解答。等客戶走后,他再開(kāi)始繼續(xù)工作。

          隨著來(lái)找他的人與日俱增,漸漸的小王發(fā)現(xiàn)他真正用于干活兒的時(shí)間越來(lái)越少了,因?yàn)樗诮哟蛻羯匣ㄙM(fèi)了太多的時(shí)間。

          但沒(méi)有辦法,為了能夠接到更多的活兒,他必須為客戶提供這個(gè)咨詢,必須要花掉這些時(shí)間。結(jié)果導(dǎo)致干活兒的時(shí)間被壓縮了,活兒干不完了,該咋辦呢?

          其實(shí)解決方法很簡(jiǎn)單,所有人都能想得到,那就是小王招了一個(gè)工人專門(mén)給他干活。工人干完活后先過(guò)小王這一關(guān),小王覺(jué)得可以了才會(huì)交付給業(yè)主。

          小王呢則繼續(xù)為客戶提供咨詢服務(wù),在空閑的時(shí)候也會(huì)去和僅有的一個(gè)工人一起干活??磥?lái)問(wèn)題已得到解決,一切重新回到平衡狀態(tài)中。

          由于小王走了狗屎運(yùn),每天來(lái)的客戶實(shí)在是太多了,這個(gè)剛剛建立的平衡又被打破了。小王不得不全天候的提供咨詢,索性不再干活了。

          而且由于接的活兒越來(lái)越多,無(wú)奈不得不又招了第二個(gè)工人,第三個(gè)工人,第四個(gè)。。。

          我們可以看到很多事情都在逐漸的發(fā)生著改變,小王從一個(gè)只會(huì)干活的工人逐步過(guò)渡到只負(fù)責(zé)接待客戶的顧問(wèn),不再干活。

          為了適應(yīng)自己的這個(gè)新角色,小王不得不招了一個(gè)又一個(gè)工人為自己干活,這樣自己才能得以從原來(lái)的工作中徹底解脫。

          可見(jiàn)隨著事物的發(fā)展,分工的產(chǎn)生是一種必然,這就導(dǎo)致了崗位種類(lèi)的增加。原來(lái)只有一個(gè)崗位,既負(fù)責(zé)干活又負(fù)責(zé)咨詢。

          現(xiàn)在變?yōu)榱藘蓚€(gè)崗位,一個(gè)專門(mén)負(fù)責(zé)咨詢和監(jiān)工,其實(shí)就是工長(zhǎng)了,一個(gè)專門(mén)負(fù)責(zé)干活和施工,其實(shí)就是工人。

          這種“工長(zhǎng) + 工人”的模式在現(xiàn)實(shí)生活中使用的非常普遍,工長(zhǎng)為工人分配工作和驗(yàn)收工人的工作以及解答工人的問(wèn)題,其實(shí)就是兩個(gè)崗位之間的協(xié)作。

          因此,分工的產(chǎn)生與協(xié)作代表著一種更加先進(jìn)和高效的生產(chǎn)方式,至少?gòu)睦碚撋蟻?lái)看是這樣的,他們各司其職,然后再?gòu)?qiáng)強(qiáng)聯(lián)合,結(jié)果可想而知。


          Web容器對(duì)異步的支持


          看完上一小節(jié),希望大家記住這八個(gè)字,“各司其職、相互協(xié)作”。OK,馬上進(jìn)入程序世界。

          SpringMvc的實(shí)質(zhì)就是對(duì)Java Web的封裝,因此為了更容易的理解SpringMvc的異步,必須先了解Java Web的異步。

          Java Web的實(shí)質(zhì)就是一套標(biāo)準(zhǔn)(接口),Web容器實(shí)現(xiàn)了這套標(biāo)準(zhǔn),所以我們站在Web容器的立場(chǎng)來(lái)說(shuō)Java Web的異步,非常好理解。

          無(wú)論采用什么框架開(kāi)發(fā)的Java Web應(yīng)用,最終都是在Web容器中運(yùn)行的,如tomcat就是最常用的Web容器。

          啟動(dòng)SpringBoot時(shí),可以看看日志中打印出的線程名稱,其實(shí)就是tomcat線程池里的線程??梢远嗾?qǐng)求幾次,發(fā)現(xiàn)每次處理請(qǐng)求的線程Id都不一樣。

          我們知道,其實(shí)每一個(gè)請(qǐng)求過(guò)來(lái)后,Web容器都會(huì)從自己的線程池中拿出一個(gè)線程來(lái)運(yùn)行Java Web應(yīng)用以處理請(qǐng)求。當(dāng)請(qǐng)求處理完后,這個(gè)線程會(huì)被還回到線程池中以便處理下一個(gè)請(qǐng)求。

          如果請(qǐng)求能在非常短的時(shí)間內(nèi)處理完成,是沒(méi)有問(wèn)題的。我們?cè)O(shè)想一下,如果請(qǐng)求執(zhí)行的非常慢,那么這個(gè)線程將無(wú)法還回去,于是線程池中可用的線程數(shù)目將少一個(gè)。

          由于線程池的容量是有限的,如果很多執(zhí)行的很慢的請(qǐng)求同時(shí)到來(lái),那么線程池中的線程將會(huì)用光,而且短時(shí)間內(nèi)都還不回來(lái)。此時(shí)的其它請(qǐng)求都將無(wú)法被處理。

          我們發(fā)現(xiàn)執(zhí)行很快的請(qǐng)求和非常耗時(shí)的請(qǐng)求是屬于兩種不同性質(zhì)的事物,現(xiàn)在它們都由Web容器的線程池的線程來(lái)從頭處理到尾,就像當(dāng)初的小王。

          既要接待客戶做咨詢工作,又要等客戶走了自己干活。這顯然是低效的,唯一的方法就是將這兩種工作分開(kāi),分別交由兩個(gè)崗位去做。

          于是我們就看到,小王招了很多工人,自己專業(yè)做咨詢接活兒,轉(zhuǎn)手把活兒交給工人去做,工人做好后把活兒再交回給小王,小王再向業(yè)主交付。

          我們可以把這個(gè)思路套到Web容器上,就是Web容器線程池的線程只用來(lái)處理執(zhí)行速度很快的請(qǐng)求,這對(duì)應(yīng)于小王只負(fù)責(zé)咨詢接活兒。

          對(duì)于非常耗時(shí)的請(qǐng)求,Web容器線程池的線程將把這個(gè)請(qǐng)求交給其它專門(mén)的線程池的線程去處理,這對(duì)應(yīng)于小王把接到的活兒交給他的工人去做。

          Web容器線程池的線程將再去接受其它請(qǐng)求,因?yàn)楹臅r(shí)的請(qǐng)求已經(jīng)被交出去了。這對(duì)應(yīng)于小王再去接別的活兒,因?yàn)樯弦粋€(gè)活兒已經(jīng)交給工人去干了。

          專門(mén)的線程池的線程處理完這個(gè)請(qǐng)求后會(huì)把它還回給Web容器線程池的線程,這對(duì)應(yīng)于工人干完活兒后會(huì)把活兒先交給小王去驗(yàn)收。

          Web容器線程池的線程拿到處理結(jié)果,把結(jié)果寫(xiě)入響應(yīng),這個(gè)請(qǐng)求就被處理完畢了。這對(duì)應(yīng)于小王把工人干好的活兒交付給業(yè)主,施工就算完畢了。

          我們來(lái)分析一下,小王由于角色轉(zhuǎn)變而帶來(lái)的工作轉(zhuǎn)變都有哪些。一開(kāi)始小王單打獨(dú)斗,小王工作有三種,小王從業(yè)主接活兒,小王自己干活,小王向業(yè)主交付。

          到最后小王成了工長(zhǎng),此時(shí)的工作是四種,小王從業(yè)主接活兒,小王把活兒交給工人去做,工人把做好的活兒交回給小王,小王向業(yè)主交付。

          對(duì)比后發(fā)現(xiàn),小王為了使自己不干活,所以引入了工人,以及由此產(chǎn)生的他與工人之間的一去一來(lái)的協(xié)調(diào)交互。

          同樣來(lái)分析一下,Web容器線程池的線程前前后后有哪些變化。一開(kāi)始線程處理所有的請(qǐng)求,可以分為三個(gè)階段,線程接受請(qǐng)求,線程處理請(qǐng)求,線程寫(xiě)回響應(yīng)。

          到最后線程的工作分為四個(gè)階段,線程接受請(qǐng)求,線程把待處理的請(qǐng)求交給專門(mén)的線程池專門(mén)的線程池把處理好的請(qǐng)求交回給線程,線程寫(xiě)回響應(yīng)。

          對(duì)比后發(fā)現(xiàn),Web容器線程池的線程為了使自己不處理耗時(shí)請(qǐng)求,所以引入了專門(mén)的線程池,以及由此產(chǎn)生的它與專門(mén)的線程池的一去一來(lái)的協(xié)調(diào)交互。

          是不是發(fā)現(xiàn)線程池和小王的行為是完全對(duì)應(yīng)的。而且他們面臨的問(wèn)題都一樣,就是把需要處理的任務(wù)交出去給別人,別人把處理完畢的任務(wù)再還回給他。

          好了,現(xiàn)在我來(lái)告訴你,這就是Java Web異步處理的整體邏輯思想?;睘楹?jiǎn)后,其實(shí)就是一去一來(lái)這兩個(gè)動(dòng)作罷了。

          自己把執(zhí)行流程交出去

          1AsyncContext?startAsync()

          別人把執(zhí)行流程還回來(lái)

          1void?dispatch()

          上面這兩個(gè)方法就完成了一去一來(lái)這兩個(gè)動(dòng)作,僅此而已。

          看到這些,可能有些人大失所望,傳說(shuō)中“牛X和高大上”的異步處理,到最后也不過(guò)區(qū)區(qū)十四個(gè)字,“執(zhí)行流程交出去,執(zhí)行流程還回來(lái)”。

          可能還會(huì)有人覺(jué)得,異步處理不應(yīng)該和客戶端也有關(guān)系嗎?其實(shí)并沒(méi)有,純粹是服務(wù)器端的把戲。而且對(duì)于單個(gè)請(qǐng)求的處理時(shí)間也不會(huì)減少。

          就像你去飯店吃飯,你點(diǎn)的這份飯?jiān)诤髲N是一個(gè)廚師完成的還是多個(gè)廚師協(xié)作完成的,其實(shí)你并不知道,一般情況下你也并不關(guān)心。


          SpringMvc對(duì)異步的支持


          上面描述的異步處理邏輯只是一個(gè)規(guī)范(接口),是不帶實(shí)現(xiàn)的。任何想要支持Java Web異步處理的,需要在遵守這個(gè)規(guī)范的前提下,自己提供一套實(shí)現(xiàn)。

          說(shuō)白了,就是也要采用交出去還回來(lái)的模式,但是如何交出去,怎樣還回來(lái),要自己去實(shí)現(xiàn),還有這個(gè)專門(mén)的線程池也要自己來(lái)提供。

          SpringMvc提供了對(duì)異步的支持,所以它遵守了這個(gè)規(guī)范,而且它也定義了相似的接口來(lái)與Java Web規(guī)范交互。

          這個(gè)接口就是AsyncWebRequest,它的實(shí)現(xiàn)類(lèi)是StandardServletAsyncWebRequest。同樣的兩個(gè)方法。

          交出去

          1void?startAsync()

          還回來(lái)

          1void?dispatch()


          在這兩個(gè)方法的實(shí)現(xiàn)中,分別去調(diào)用了Java Web規(guī)范中的對(duì)應(yīng)方法,這就是與Java Web規(guī)范的交互。

          同時(shí)SpringMvc自己是有線程池的,所以在第一個(gè)方法里實(shí)現(xiàn)了把執(zhí)行流程交出去的操作,在第二個(gè)方法里實(shí)現(xiàn)了把執(zhí)行流程還回來(lái)的操作。

          還有一個(gè)問(wèn)題就是,并不是所有的方法都需要異步處理,所以就需要有一種方式來(lái)告訴SpringMvc,哪個(gè)方法需要異步處理。

          SpringMvc選擇了采用方法返回值的類(lèi)型來(lái)進(jìn)行區(qū)分,凡是@RequestMapping方法的返回值類(lèi)型是以下這些的,就表明開(kāi)發(fā)人員想進(jìn)行異步處理,于是SpringMvc就進(jìn)行異步處理。

           1Callable<V>
          2
          3DeferredResult<T>
          4
          5WebAsyncTask<V>
          6
          7StreamingResponseBody
          8
          9ResponseEntity<StreamingResponseBody>
          10
          11ResponseBodyEmitter
          12
          13ResponseEntity<ResponseBodyEmitter>

          對(duì)于異步處理的方式,其實(shí)也包括兩大類(lèi),一類(lèi)是開(kāi)發(fā)人員不管,完全交給SpringMvc去處理,一類(lèi)是開(kāi)發(fā)人員自己把控,不用SpringMvc參與。

          對(duì)于第一類(lèi),我們返回Callable類(lèi)型就可以了,這樣SpringMvc會(huì)把它提交到線程池里去執(zhí)行。

          b02824fd8853984251f86fdbb6be9a07.webp


          對(duì)于第二類(lèi),
          我們返回DeferredResult類(lèi)型即可,它的意思是延遲結(jié)果,就是需要延遲一會(huì)才會(huì)有結(jié)果,但是如何延遲呢,SpringMvc并不會(huì)去管。

          cf512b641b33edf2fb13e6434bd2ac98.webp


          因此是由開(kāi)發(fā)人員來(lái)決定的,開(kāi)發(fā)人員需要自己弄個(gè)線程去執(zhí)行,并且一定要記住
          最后要設(shè)置一下結(jié)果才行。

          我們看到耗時(shí)的代碼都跑到別的線程里去執(zhí)行了,那么SpringMvc的處理主流程自然就結(jié)束了,這就是執(zhí)行流程交出去的過(guò)程。

          只不過(guò)有一點(diǎn)需要注意,這個(gè)請(qǐng)求的處理并沒(méi)有完成,只是暫時(shí)離開(kāi)了SpringMvc的主流程,在別的線程池里運(yùn)行著呢。

          那么一段時(shí)間后,別的線程池運(yùn)行結(jié)束,已經(jīng)取得了結(jié)果,那這個(gè)結(jié)果和執(zhí)行流程又該如何還回來(lái)呢?

          直接還回來(lái)嗎?顯然是不可能的,因?yàn)镾pringMvc的處理主流程在把任務(wù)交出去的那一刻就已經(jīng)結(jié)束了、不存在了。

          其實(shí)是別的線程池在處理結(jié)束并得到結(jié)果后,處理流程連同結(jié)果會(huì)返回到Web容器中,由Web容器再次分派這個(gè)請(qǐng)求到SpringMvc中來(lái)。

          這就是為什么上面第二個(gè)方法的名字叫做dispatch的原因,就是再次分派這個(gè)請(qǐng)求到Web應(yīng)用中來(lái)嘛,因此會(huì)再次進(jìn)入到SpringMvc中,這不就把執(zhí)行流程還回來(lái)了嘛。

          可能會(huì)有人產(chǎn)生疑惑,如果SpringMvc再次處理這個(gè)請(qǐng)求那不就亂套了嗎?答案是顯然不會(huì)的,因?yàn)檫@次異步的結(jié)果已經(jīng)存在了,自然不會(huì)再異步處理了,而是把它跳過(guò)去直接進(jìn)入后續(xù)處理。

          也就是對(duì)方法返回值(ReturnValue)的處理,比如序列化成JSON寫(xiě)入響應(yīng),或進(jìn)行視圖渲染,把渲染后的視圖寫(xiě)入響應(yīng),這樣這個(gè)請(qǐng)求就算處理完畢了。

          歡迎加入交流群學(xué)習(xí),備注加群說(shuō)實(shí)話在這個(gè)群,哪怕您不說(shuō)話,光看聊天記錄,都能學(xué)到東西


          兩年嘔心瀝血的文章「面試題」「基礎(chǔ)」「進(jìn)階」這里全都有!

          300多篇原創(chuàng)技術(shù)文章加入交流群學(xué)習(xí)海量視頻資源精美腦圖面試題

          長(zhǎng)按掃碼可關(guān)注獲取?

          在看和分享對(duì)我非常重要!eb2067d7cba72523e6f020ff0780f2ec.webp

          瀏覽 45
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  视频一区二区三区在线观看 | 日韩 欧美中文字幕第一页在线 | 国产公妇乱婬XXXX看一本毛片 | 另类天堂 | 天天撸夜夜干 |