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

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 四虎永久免费地址 | 免费视频片在线观看 | youjizzxxx在线观看 | 国产欧美日韩图片一区二区 | 久久久精品3d动漫一区二区三区 | 亚洲欧美综合一区 | 亚洲高清在线天堂精品 | 操美女bb| 咪咪爱网友自拍 | 黄网在线观看免费网站台湾swag | 精品综合久久久久久88小说 | 国产va免费精品高清在线观看 | 亚洲国产成人99精品激情在线 | 亚洲精品国产成人 | 邪恶肉肉全彩色无遮琉璃神社 | 国产日本久久久久久久久婷婷 | 国产精品欧美韩国日本久久 | 99久久免费国内精品 | 国产成人综合亚洲亚洲欧美 | 毛片在线免费视频 | 和直男装修工在工地啪 | 精品视频久久久久 | 九九精品国产亚洲A片无码 九九99热久久999精品 | 被老外操 | 婷婷色综合网 | 91久久偷偷做嫩草影院免费看 | 日韩伦理在线看 | 国产伦精品一区二区三区免 | 国产91精品在线观看 | 成全视频在线观看免费 | 成人免费网站视频ww | 波多野结衣作品在线观看 | 美女被爆操 | 91精品手机国产在线观 | 国产馆 | 大陆国语自产精品视频在 | 91精品国产亚一区二区三区 | 红色毛片 | a男人的天堂久久a毛片 | 国产亚洲玖玖玖在线观看 | 国产欧美成人免费观看 |