一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 詳解Spring DeferredResult異步操作使用場景

詳解Spring DeferredResult異步操作使用場景

2022-02-27 15:22yangguoqi Java教程

本文主要介紹了Spring DeferredResult異步操作使用場景,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

為什么使用DeferredResult

API接口需要在指定時間內將異步操作的結果同步返回給前端時;

Controller處理耗時任務,并且需要耗時任務的返回結果時;

當一個請求到達API接口,如果該API接口的return返回值是DeferredResult,在沒有超時或者DeferredResult對象設置setResult時,接口不會返回,但是Servlet容器線程會結束,DeferredResult另起線程來進行結果處理(即這種操作提升了服務短時間的吞吐能力),并setResult,如此以來這個請求不會占用服務連接池太久,如果超時或設置setResult,接口會立即返回。

使用DeferredResult的流程:

  • 瀏覽器發起異步請求
  • 請求到達服務端被掛起
  • 向瀏覽器進行響應,分為兩種情況:
    • 調用DeferredResult.setResult(),請求被喚醒,返回結果
    • 超時,返回一個你設定的結果
  • 瀏覽得到響應,再次重復1,處理此次響應結果

給人一種異步處理業務,但是卻同步返回的感覺。

 

場景

瀏覽器向A系統發起請求,該請求需要等到B系統(如MQ)給A推送數據時,A才會立刻向瀏覽器返回數據;

如果指定時間內B未給A推送數據,則返回超時。

 

Demo代碼

接口代碼:

/get是調用A系統的接口返回數據;

/result模擬B系統向A推送數據進行setResult。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;


@RestController
@RequestMapping(value = "/deferred-result")
public class DeferredResultController {

  @Autowired
  private DeferredResultService deferredResultService;

  /**
   * 為了方便測試,簡單模擬一個
   * 多個請求用同一個requestId會出問題
   */
  private final String requestId = "haha";


  @GetMapping(value = "/get")
  public DeferredResult<DeferredResultResponse> get(@RequestParam(value = "timeout", required = false, defaultValue = "10000") Long timeout) {
      DeferredResult<DeferredResultResponse> deferredResult = new DeferredResult<>(timeout);

      deferredResultService.process(requestId, deferredResult);

      return deferredResult;
  }

  /**
   * 設置DeferredResult對象的result屬性,模擬異步操作
   * @param desired
   * @return
   */
  @GetMapping(value = "/result")
  public String settingResult(@RequestParam(value = "desired", required = false, defaultValue = "成功") String desired) {
      DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
      if (DeferredResultResponse.Msg.SUCCESS.getDesc().equals(desired)){
          deferredResultResponse.setCode(HttpStatus.OK.value());
          deferredResultResponse.setMsg(desired);
      }else{
          deferredResultResponse.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
          deferredResultResponse.setMsg(DeferredResultResponse.Msg.FAILED.getDesc());
      }
      deferredResultService.settingResult(requestId, deferredResultResponse);

      return "Done";
  }
}
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

@Service
public class DeferredResultService {

  private Map<String, Consumer<DeferredResultResponse>> taskMap;

  public DeferredResultService() {
      taskMap = new ConcurrentHashMap<>();
  }

  /**
   * 將請求id與setResult映射
   *
   * @param requestId
   * @param deferredResult
   */
  public void process(String requestId, DeferredResult<DeferredResultResponse> deferredResult) {
      // 請求超時的回調函數
      deferredResult.onTimeout(() -> {
          taskMap.remove(requestId);
          DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
          deferredResultResponse.setCode(HttpStatus.REQUEST_TIMEOUT.value());
          deferredResultResponse.setMsg(DeferredResultResponse.Msg.TIMEOUT.getDesc());
          deferredResult.setResult(deferredResultResponse);
      });

      Optional.ofNullable(taskMap)
              .filter(t -> !t.containsKey(requestId))
              .orElseThrow(() -> new IllegalArgumentException(String.format("requestId=%s is existing", requestId)));

      // 這里的Consumer,就相當于是傳入的DeferredResult對象的地址
      // 所以下面settingResult方法中"taskMap.get(requestId)"就是Controller層創建的對象
      taskMap.putIfAbsent(requestId, deferredResult::setResult);
  }

  /**
   * 這里相當于異步的操作方法
   * 設置DeferredResult對象的setResult方法
   *
   * @param requestId
   * @param deferredResultResponse
   */
  public void settingResult(String requestId, DeferredResultResponse deferredResultResponse) {
      if (taskMap.containsKey(requestId)) {
          Consumer<DeferredResultResponse> deferredResultResponseConsumer = taskMap.get(requestId);
          // 這里相當于DeferredResult對象的setResult方法
          deferredResultResponseConsumer.accept(deferredResultResponse);
          taskMap.remove(requestId);
      }
  }

}
import lombok.Data;
import lombok.Getter;

@Data
public class DeferredResultResponse {
  private Integer code;
  private String msg;

  public enum Msg {
      TIMEOUT("超時"),
      FAILED("失敗"),
      SUCCESS("成功");

      @Getter
      private String desc;

      Msg(String desc) {
          this.desc = desc;
      }
  }
}

 

測試

1. 超時

設置超時時間為8s,會一直阻塞8s,如果超時,返回默認超時的結果

詳解Spring DeferredResult異步操作使用場景

8s過去,沒有setResult,返回超時

詳解Spring DeferredResult異步操作使用場景

2. 進行setResult

在阻塞期間調用setResult,我這里模擬的是B系統推送數據給A時拋異常失敗的情況,會立刻得到返回結果

詳解Spring DeferredResult異步操作使用場景

詳解Spring DeferredResult異步操作使用場景

 

總結:

當有前端需要一個耗時操作服務時,可以使用DeferredResult異步機制編寫代碼。如果不用此功能,要么自己實現類似的功能。要么是前端輪訓去拉處理的結果,開發量比較大。有了DeferredResult可以節省很多我們前后端的開發量。

到此這篇關于詳解Spring DeferredResult異步操作使用場景的文章就介紹到這了,更多相關Spring DeferredResult異步內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/yangguoqi/article/details/106817137

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 秒播影视 午夜福利毛片 | 俄罗斯三级完整版在线观看 | 99热综合在线 | 肉性天堂| 国产午夜亚洲精品 | 亚洲国产婷婷俺也色综合 | 亚洲精品动漫免费二区 | 午夜国产精品福利在线观看 | 日本视频免费看 | 国产高清一区二区三区免费视频 | 国产三级自拍视频 | 91无套极品外围在线播放 | 成熟女人50岁一级毛片不卡 | 富士av105| 国产精品青青青高清在线观看 | 2019午夜福合集高清完整版 | 韩国甜性涩爱在线播放 | 色噜噜国产精品视频一区二区 | 国产白白视频在线观看2 | 午色影院 | 亚洲不卡视频 | 女主被男主做哭失禁高h | 免费在线视频一区 | 午夜影院费试看黄 | a级片欧美 | 欧美一区二区三区gg高清影视 | 日韩欧美亚洲一区二区综合 | 欧美日韩综合网在线观看 | www四虎影视 | 国产精品秒播无毒不卡 | 麻豆小视频在线观看 | 欧美同性猛男野外gay免费 | 国内精品久久久久久久久久久久 | 亚洲AVAV天堂AV在线网爱情 | 国产高清小视频 | 精品国产福利在线 | 国产原创一区二区 | 日韩香蕉网 | jizzjizz大学生| 精品视频国产 | 免费成人在线观看视频 |