
image.png
上節(jié)課我們做了一個用戶的Controller并且得到了用戶的詳細(xì)信息和用戶列表
這部分內(nèi)容都是我們寫死的 并且都是靜態(tài)的數(shù)據(jù)
接下來我們模擬一下比較耗時的操作(比如操作數(shù)據(jù)庫 操作其他服務(wù)的接口)調(diào)用的時候都會出現(xiàn)一些延時
為了演示簡單 我們這里使用sleep方法對我們操作進(jìn)行延時的模擬
接下來我們寫下代碼
比如我們要增加用戶
首先我們在userInfo里面加入toString的重載方法

image.png
接下來在UsersController中寫增加用戶的api

image.png
寫完后我們重新編譯代碼
用火狐帶的插件測試接口(為了演示火狐插件跨域問題 我這里將context-spring.xml中全局配置 跨域請求設(shè)置允許所有域名訪問了)
如下

image.png
*表示不限制域名 把上節(jié)課的8999端口配置注釋掉了
設(shè)置contype

image.png
body中參數(shù)和我們userInfo實(shí)體類字段一致如下

image.png
點(diǎn)擊send

image.png
可以看見圓圈在轉(zhuǎn) 因為有3s延時
3s后結(jié)果如下

image.png
下面我們思考下 這樣的話是否會有問題 因為我們在實(shí)際網(wǎng)站運(yùn)行過程當(dāng)中很可能一個請求處理數(shù)據(jù)庫或其余的業(yè)務(wù)都會造成一定時間的卡頓 這時會不會讓我們的服務(wù)器出現(xiàn)無法響應(yīng)或無法請求 肯定會有這種情況
其中有一種情況,下面我們看張圖

image.png
實(shí)際上tomcat內(nèi)部是一個多線程處理請求的一個過程 當(dāng)瀏覽器發(fā)出一個request請求時 tomcat會專門給一個線程來處理這個請求 處理過程中如果代碼里面有比較耗時的操作(數(shù)據(jù)庫操作或其他操作)會阻塞當(dāng)前的線程 也就是說這時 當(dāng)前線程是不能接受其他瀏覽器發(fā)起的request請求,如果再有一個其他瀏覽器發(fā)起request請求 要么由其他線程來處理新的請求 要么如果線程不夠了 就剩之前的那一個線程的話,那么這個請求必須進(jìn)入等待的隊伍 因此我們需要使用異步的過程
異步過程大致如下

image.png
比如說瀏覽器發(fā)起請求 這時tomcat的線程可以把相關(guān)的任務(wù)操作(比如數(shù)據(jù)庫操作部分)交給另外一個單獨(dú)線程來處理,此時當(dāng)前線程就不會阻塞,如果此時再來一個瀏覽器請求,他就可以繼續(xù)處理里面的過程,然后單獨(dú)線程處理好之后,啟用一個回調(diào)線程,把里面的數(shù)據(jù)響應(yīng)給我們的客戶端(瀏覽器端) 我們使用這種單獨(dú)線程(實(shí)際上還可以設(shè)置一些線程池)對我們的tomcat(或者其他web服務(wù)器)可以起到提高吞吐量的過程
下面看下代碼

image.png
spring里面對異步是如何支持的
看下文檔
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-async
spring5.0文檔說明如下

image.png
servlet3以后 Spring3.2就支持了異步請求 處理我們業(yè)務(wù)邏輯 當(dāng)我們返回值的時候 需要返回Callable(其中一種) 這時我們主線程就釋放掉了去處理其他的請求了 而TaskExecuter是來處理單獨(dú)線程 處理好之后 這個request會回到我們servlet容器中返回給我們的客戶端
以上就是基本過程
下面上代碼

image.png
首先我們要在webapp的WEB-INF下面的web.xml的servlet中加入異步支持
web.xml中加入如下

image.png
接下來對代碼進(jìn)行異步改造
在UsersController中

image.png
接下來發(fā)布運(yùn)行下代碼
下面準(zhǔn)備個test1.html文件 存放在localhost:8999域名的web服務(wù)器上
目錄如下

image.png
里面寫如下代碼

image.png
由于我們后端api返回的是字符串 所以需要用到response.text()
接下來我們訪問下test1.html

image.png
這時我們點(diǎn)擊異步提交按鈕 結(jié)果如下
卡頓3s彈出結(jié)果(服務(wù)端提供的結(jié)果)

image.png
在google瀏覽器打開network 點(diǎn)擊異步提交 出現(xiàn)如下 pending字樣(3s卡頓)

image.png
3s后

image.png
彈出結(jié)果 pending也消失了(服務(wù)端處理完成之后 把響應(yīng)返回給前端)
使用異步 在我們后端web服務(wù)器端 提高了處理速度和吞吐量
接下來我們看下 其實(shí)這樣做沒什么感覺 如何讓自己有感覺呢
我們首先來測試下 改下tomcat tomcat里有些參數(shù)在我們之前沒有涉及到 我們可以查一下tomcat的調(diào)優(yōu)設(shè)置
比如我們今天的設(shè)置tomcat的最大線程數(shù)

image.png
tomcat里默認(rèn)里面有200個線程對我們的請求進(jìn)行處理 所以上面我們處理這種請求毫無感覺
下面我在改造下代碼(看下例子)
修改test1.html

image.png
增加了以上三處
加入了同步的按鈕
然后再java代碼
UsersController中加入如下代碼

image.png
下面重新發(fā)布下代碼
看看新增的兩個方法的區(qū)別
首先看下前端頁面

image.png
分別表示異步提交 同步提交有延時(后端代碼sleep了3s) 和同步提交無延時
下面看下效果
首先點(diǎn)擊同步無延時按鈕

image.png
可以發(fā)現(xiàn)立即就彈出了窗口信息
接下來點(diǎn)擊同步有延時按鈕

image.png

image.png
延時了3s
當(dāng)我們點(diǎn)同步有延時按鈕時 在3s內(nèi)點(diǎn)擊同步無延時按鈕
可以發(fā)現(xiàn)同步無延時按鈕點(diǎn)擊后立刻還能做出響應(yīng) 這是因為tomcat內(nèi)部默認(rèn)有200個線程處理請求
所以在我們請求數(shù)很少的情況下是沒有問題的
如果我們的請求數(shù)太多 不夠了 那么就會出現(xiàn)問題
怎么能不夠 需要更改tomcat參數(shù)
下面我們打開tomcat的配置文件

image.png
Connector里面可以加入默認(rèn)參數(shù)
加入這個參數(shù)

image.png
我們添加如下

image.png
把tomcat最大請求數(shù) 設(shè)置成了1
當(dāng)前只有一個線程 處理我們的請求
重啟下服務(wù) 查看效果
我們點(diǎn)擊同步無延時按鈕

image.png
還是很快的彈出信息框
我們在點(diǎn)擊同步有延時按鈕 3s內(nèi)在點(diǎn)同步無延時按鈕

image.png
可以發(fā)現(xiàn)頁面沒有響應(yīng)
3s后

image.png
點(diǎn)擊確定 再次彈出信息框

image.png
是因為我們先點(diǎn)擊同步有延時按鈕
tomcat的線程只有一個 所以當(dāng)前線程不能處理 后來的同步無延時按鈕的請求
需要等待3s后才能執(zhí)行后來的同步無延時按鈕請求
所以先彈出的是有延時的 緊接著無延時的也彈出了
那么我們在測試下異步按鈕(就不會出現(xiàn)上面的問題)
我們先點(diǎn)擊異步按鈕 在點(diǎn)擊同步無延時按鈕
因為異步也是延時了3s
當(dāng)我們點(diǎn)擊完異步按鈕 在3s內(nèi)點(diǎn)擊同步無延時按鈕

image.png
過幾秒又彈出

image.png
這是因為我們異步代碼把剛才的線程已經(jīng)釋放掉了 可以用來處理新的請求