成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

徹底搞懂Web異步編程模型

開發(fā) 前端
今天我們系統(tǒng)分析了在 Web 應(yīng)用程序開發(fā)過程中,如何使用 Spring 框架提供的異步編程能力來提高系統(tǒng)的響應(yīng)性。

長期以來,Spring Web MVC 運(yùn)行在 Tomcat、JBoss 等 Servlet 容器上,是我們開發(fā) Web 服務(wù)的主流框架。但你要注意的是,Servlet 容器是阻塞式的,所以 WebMVC 也建立在阻塞 I/O 之上。

換句話說,任何一個請求的響應(yīng)過程都是同步的,需要在服務(wù)器工作線程接收請求、阻塞等待 I/O 以及完成請求處理之后才能返回。

圖 1 同步請求處理過程示意圖圖 1 同步請求處理過程示意圖

這樣的同步請求處理機(jī)制對普通應(yīng)用場景來說是合適的,但在一些特定場景下,這種同步機(jī)制會存在局限性,需要開發(fā)人員采用異步的方式來處理 Web 請求。這就引出了今天我們要討論的主題,Web 異步編程模型。

讓我們先從 Web 異步處理需求和場景開始說起。

Web 異步處理需求和場景

Web 異步處理的第一個應(yīng)用場景是為了 提升系統(tǒng)性能

我們知道,同步請求處理機(jī)制采用的是一個請求對應(yīng)一個線程的實(shí)現(xiàn)過程。這樣,系統(tǒng)請求數(shù)量越大,我們就需要創(chuàng)建越多的線程,而線程是一種資源,系統(tǒng)的響應(yīng)能力會隨著資源的消耗而逐漸下降。但異步處理機(jī)制不需要在處理請求時全程保持某一個線程,這樣線程資源就能做到復(fù)用。

圖 2 異步請求處理過程示意圖圖 2 異步請求處理過程示意圖

接下來是異步處理的第二個應(yīng)用場景,對于有些請求而言,我們實(shí)際上并不關(guān)注請求的返回結(jié)果,也就是說這些請求采用的是一種 即發(fā)即棄(Fire and Forget)模式

這個模式有點(diǎn)類似于消息中間件的處理過程,請求線程發(fā)送請求然后直接返回。如果采用同步模式,那么請求必須等待服務(wù)端返回。因此,相比于異步處理,同步模式會造成浪費(fèi)。

圖 3 即發(fā)即棄處理過程示意圖圖 3 即發(fā)即棄處理過程示意圖

最后,異步處理的第三種場景,在日常開發(fā)過程中, 某個請求需要處理大量業(yè)務(wù)數(shù)據(jù),這也是我們會經(jīng)常碰到的情況。比較典型的例子就是導(dǎo)出數(shù)據(jù)報(bào)表。在這種場景下,如果采用同步模式,很可能會導(dǎo)致出現(xiàn)請求超時。

這時候,合理的解決方案是先對請求做出快速響應(yīng),然后再啟動異步線程來執(zhí)行大數(shù)據(jù)處理邏輯。

圖 4 大數(shù)量請求處理過程示意圖圖 4 大數(shù)量請求處理過程示意圖

現(xiàn)在來簡單總結(jié)一下,從三個特定場景的異步模式應(yīng)用中,我們可以看出:

對于傳統(tǒng)請求場景,異步模式能夠確保線程復(fù)用;

對于即發(fā)即棄場景,異步模式能夠節(jié)省系統(tǒng)資源;

而對于大數(shù)量請求場景,異步模式則能夠提高用戶體驗(yàn)。

所以,如果能夠在復(fù)雜的業(yè)務(wù)場景中集成這三種場景中的異步調(diào)用機(jī)制,我們就可以高效處理 Web 請求。

那么,應(yīng)該如何使用異步模式來高效應(yīng)對這些場景呢?Spring 為我們提供了完整的解決方案,我們一起來看一下。

Spring Web 異步編程模型

異步處理的主要優(yōu)勢是調(diào)用方不必等待被調(diào)用方完成執(zhí)行過程,這就需要啟動新的線程。為了在一個新的線程中執(zhí)行目標(biāo)方法,Spring 異步編程模型提供了一個全新的@Async 注解。該注解可以與 JDK 中的 Future 機(jī)制以及線程池進(jìn)行無縫整合。我們先來看這個@Async 注解。

@Async 注解

想要在 Spring 應(yīng)用程序中啟用異步編程模式,我們可以通過@EnableAsync 注解實(shí)現(xiàn)這一目標(biāo)。常見的做法是在 Spring 配置類上添加這一注解。

@Configuration
@EnableAsync
public class SpringConfig { ... }

@Async 注解支持兩種處理模式,即 即發(fā)即棄模式和普通的請求響應(yīng)模式。我們先來看即發(fā)即棄模式的代碼示例。

@Async
public void recordUserHealthData() {
 logger.info("Record user health data successfully.");
}

可以看到,我們在一個返回值為 void 的方法上添加了@Async 注解,這樣該方法中將以異步的方式進(jìn)行執(zhí)行。

然后,我們來看一下請求響應(yīng)式的異步方式代碼示例。

@Service
public class HealthService {
    @Async
    public Future<String> getHealthDescription() throws InterruptedException {
        LOGGER.info("Thread id: " + Thread.currentThread().getId());
        //睡眠 2 秒
        Thread.sleep(2000);
        String healthDescription = “health description”;
        LOGGER.info(processInfo);
        return new AsyncResult<String>(healthDescription);
    }
}

可以看到,這里我們在方法入口打印了當(dāng)前的線程 ID,然后讓主線程睡眠 2 秒用來模擬長時間的業(yè)務(wù)處理流程。接著,我們返回異步調(diào)用的結(jié)果對象 AsyncResult。

AsyncResult 是 Spring 框架對 JDK 中 Future 接口的一種實(shí)現(xiàn),我們可以通過 AsyncResult 對象跟蹤異步調(diào)用的結(jié)果。為了更好理解上述方法的執(zhí)行過程,我們有必要先來看看 JDK 中的 Future 對象。

傳統(tǒng)模式調(diào)用和 Future 模式調(diào)用的對比可以參考圖 5。我們看到在 Future 模式調(diào)用過程中,客戶端在向服務(wù)器端發(fā)起請求之后馬上返回,可以繼續(xù)執(zhí)行其他任務(wù)直到服務(wù)器端通知 Future 調(diào)用的結(jié)果,體現(xiàn)了 Future 調(diào)用異步化特點(diǎn)。

圖 5 傳統(tǒng)調(diào)用(左)和 Future 機(jī)制(右)對比示意圖圖 5 傳統(tǒng)調(diào)用(左)和 Future 機(jī)制(右)對比示意圖

但原生的 Future 也有同步等待問題,因?yàn)橥ㄟ^ Future 對象直接獲取調(diào)用結(jié)果同樣會導(dǎo)致線程等待。為了解決這個問題,Java 8 中引入了 CompletableFuture 對原生的 Future 進(jìn)行了優(yōu)化,可以直接通過 CompletableFuture 將異步執(zhí)行結(jié)果交給另外一個異步線程來處理。這樣在異步任務(wù)完成后,我們在獲取任務(wù)結(jié)果時則不需要等待。

例如,如果想要在異步執(zhí)行任務(wù)完成之后返回值,那么可以使用 CompletableFuture 的 supplyAsync() 方法,示例代碼如下所示。

@RequestMapping(value = "/health_description")
public CompletableFuture<String> syncHealthDescription () {
 CompletableFuture.supplyAsync(new Supplier<String>() {
           @Override
           public String get() {
               try {
                   return healthService.getHealthDescription().get();
               } catch (InterruptedException | ExecutionException e) {
                   LOGGER.error(e);
               }
               return"No health description found";
           }
        });
        return completableFuture;
}

WebAsyncTask

前面介紹的@Async 注解實(shí)際上是通用的,我們可以用它來完成包含 Web 請求在內(nèi)的任意場景下的異步處理流程。而隨著 Spring Boot 的誕生,也出現(xiàn)了 WebAsyncTask 這一專門針對 Web 場景下的異步執(zhí)行組件。

相較@Async 注解,WebAsyncTask 為開發(fā)人員提供了更靈活的異步任務(wù)處理機(jī)制,并內(nèi)置了異步回調(diào)、超時處理和異常處理。如果想要初始化一個 WebAsyncTask 對象,我們需要設(shè)置一個超時時間,并啟動一個線程對象。

public WebAsyncTask(long timeout, Callable<V> callable)

基于這一使用方式,我們先來看一下 WebAsyncTask 的簡單示例。

@RequestMapping(value = "task_normal", method = RequestMethod.GET)
public WebAsyncTask<String> task1() {
        System.out.println("The main Thread name is " +
Thread.currentThread().getName());
        // 此處模擬開啟一個異步任務(wù)
       WebAsyncTask<String> task1 = new WebAsyncTask<String>(4 * 1000L, () -> {
           System.out.println("The first Thread name is " +
Thread.currentThread().getName());
           Thread.sleep(2 * 1000L);
           return"task1 executed!";
        });
        // 任務(wù)執(zhí)行完成時調(diào)用該方法
        task1.onCompletion(() -> {
           System.out.println("task1 finished!");
        });
        // 可以繼續(xù)執(zhí)行其他操作
        System.out.println("task1 can do other things!");
        return task1;
}

可以看到,這里初始化了一個 WebAsyncTask 對象,并設(shè)置任務(wù)的超時時間為 4s。異步任務(wù)執(zhí)行采用 Thread.sleep 方法來進(jìn)行模擬,這里設(shè)置異步線程的睡眠時間為 2s。然后,我們還通過 WebAsyncTask 的 onCompletion() 方法指定了任務(wù)執(zhí)行完成時的回調(diào)函數(shù)。

執(zhí)行以上代碼,我們在控制臺可以得到如下日志信息。

The main Thread name is http-nio-7000-exec-5
task1 can do other things!
The first Thread name is MvcAsync2
task1 finished!

顯然,我們先打印出了主線程的名稱,然后主線程可以繼續(xù)執(zhí)行并返回結(jié)果。然后我們啟動異步線程,并打印出該線程的名稱。當(dāng)異步線程執(zhí)行完畢時,同樣打印出了這一信息。如果你在瀏覽器中訪問這個 HTTP 端點(diǎn),那么可以獲取異步方法的正常返回值"task1 executed!"。

我們接著來看一下如何設(shè)置異常處理回調(diào)的方法,示例代碼如下所示。

@RequestMapping(value = "task_error", method = RequestMethod.GET)
public WebAsyncTask<String> getUserWithError() {
        System.out.println("The main Thread name is "
+ Thread.currentThread().getName());
        // 此處模擬開啟一個異步任務(wù)
       WebAsyncTask<String> task3 = new WebAsyncTask<String>(4 * 1000L, () -> {
           System.out.println("The second Thread name is "
+ Thread.currentThread().getName());
           int num = 1 / 0;
           System.err.println(num);
           return"";
        });
        // 發(fā)生異常時調(diào)用該方法
        task3.onError(() -> {
           System.err.println(Thread.currentThread().getName());
           System.err.println("task3 error occured!");
           return"";
        });
        // 任務(wù)執(zhí)行完成時調(diào)用該方法
        task3.onCompletion(() -> {
           System.out.println("task3 finished!");
        });
        // 可以繼續(xù)執(zhí)行其他操作
        System.out.println("task3 can do other things!");
        return task3;
}

這里設(shè)置了一個 onError() 回調(diào),并通過除 0 操作觸發(fā)了這一回調(diào),結(jié)果如下所示。

The main Thread name is http-nio-7000-exec-10
task3 can do other things!
The second Thread name is MvcAsync4
http-nio-7000-exec-1
task3 error occured!
task3 finished!

這樣,基于 WebAsyncTask 的異步編程模型就介紹完畢了。從上文中我們可以看出,WebAsyncTask 除了能夠?qū)崿F(xiàn)異步調(diào)用,它所提供的異步編程模型充分考慮了異步執(zhí)行過程中可能出現(xiàn)的異常情況和超時機(jī)制。同時,基于回調(diào)的異步處理結(jié)果的獲取過程也顯得非常自然。相比@Async 注解,WebAsyncTask 的功能更加強(qiáng)大。

所以,在日常開發(fā)過程中,我建議你使用這個工具類來實(shí)現(xiàn)對 Web 請求的異步處理。

總結(jié)

今天我們系統(tǒng)分析了在 Web 應(yīng)用程序開發(fā)過程中,如何使用 Spring 框架提供的異步編程能力來提高系統(tǒng)的響應(yīng)性。

我們從異步處理場景講起,引出 Spring 中所提供了@Async 注解,該注解是對異步處理過程的抽象。在具體使用過程中,我們一般結(jié)合 CompletableFuture 來處理異步線程之間的交互過程。同時,針對 Web 開發(fā)場景,Spring 還專門提供了一個 WebAsyncTask 工具類來簡化開發(fā)過程。

在日常開發(fā)過程中,@Async 注解為開發(fā)人員提供的是一種通用型的異步編程,我們可以使用它在應(yīng)用程序的各層組件中添加異步處理機(jī)制。而 WebAsyncTask 則專門面向 Web 請求處理,因此,如果你正在開發(fā) Web 應(yīng)用程序,那么 WebAsyncTask 無疑是你的首選。

責(zé)任編輯:武曉燕 來源: 程序員技術(shù)充電站
相關(guān)推薦

2022-04-12 08:00:17

socket 編程網(wǎng)絡(luò)編程網(wǎng)絡(luò) IO 模型

2025-05-06 01:14:00

系統(tǒng)編程響應(yīng)式

2020-10-14 08:50:38

搞懂 Netty 線程

2013-04-01 15:38:54

異步編程異步編程模型

2025-04-21 04:00:00

2024-03-15 08:23:26

異步編程函數(shù)

2024-09-04 16:19:06

語言模型統(tǒng)計(jì)語言模型

2024-01-03 13:39:00

JS,Javascrip算法

2023-10-18 10:55:55

HashMap

2025-04-11 05:55:00

2025-01-13 16:00:00

服務(wù)網(wǎng)關(guān)分布式系統(tǒng)架構(gòu)

2017-12-05 17:44:31

機(jī)器學(xué)習(xí)CNN卷積層

2025-06-30 00:32:43

策略模式算法MyBatis

2021-12-29 17:29:07

KubernetesEvents集群

2023-09-28 08:15:05

SpringBean加載

2021-10-11 11:58:41

Channel原理recvq

2023-05-29 08:12:38

2021-10-09 19:05:06

channelGo原理

2025-03-17 00:21:00

2009-11-09 10:43:51

WCF Web編程模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 久久69精品久久久久久国产越南 | 一级片子 | 亚洲欧美另类在线观看 | 伊人网综合在线观看 | 国产亚洲欧美日韩精品一区二区三区 | 一区二区免费在线观看 | 中文字幕精品视频 | 黄色91在线 | 欧美日韩专区 | 成人免费视频观看视频 | 美女国产一区 | 无码一区二区三区视频 | 狠狠操狠狠操 | 在线免费视频一区 | 久久久久久亚洲欧洲 | 欧美日韩在线一区二区 | 在线成人免费视频 | 中文字幕在线剧情 | 午夜a√| 先锋av资源在线 | 欧美在线一区二区三区 | aaa在线| 超碰在线亚洲 | 无码日韩精品一区二区免费 | 91精品国产综合久久精品图片 | 久久久久国产精品一区 | 久久人体视频 | 国产激情在线 | 伊人网综合| 美女国产| a在线视频 | 欧美亚洲国产精品 | 色橹橹欧美在线观看视频高清 | 久久黄色精品视频 | 在线视频一区二区 | 激情毛片| 一区二区三区不卡视频 | 高清国产午夜精品久久久久久 | 九九综合 | 在线视频日韩精品 | www.中文字幕.com |