最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringMVC異步處理操作(Callable和DeferredResult)

 更新時(shí)間:2021年01月20日 09:29:29   作者:coder_rad  
這篇文章主要介紹了SpringMVC異步處理操作(Callable和DeferredResult),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

官方文檔中說(shuō)DeferredResult和Callable都是為了異步生成返回值提供基本的支持。簡(jiǎn)單來(lái)說(shuō)就是一個(gè)請(qǐng)求進(jìn)來(lái),如果你使用了DeferredResult或者Callable,在沒(méi)有得到返回?cái)?shù)據(jù)之前,DispatcherServlet和所有Filter就會(huì)退出Servlet容器線(xiàn)程,但響應(yīng)保持打開(kāi)狀態(tài),一旦返回?cái)?shù)據(jù)有了,這個(gè)DispatcherServlet就會(huì)被再次調(diào)用并且處理,以異步產(chǎn)生的方式,向請(qǐng)求端返回值。

這么做的好處就是請(qǐng)求不會(huì)長(zhǎng)時(shí)間占用服務(wù)連接池,提高服務(wù)器的吞吐量。

Callable

@GetMapping("/callable")
 public Callable<String> testCallable() throws InterruptedException {
  log.info("主線(xiàn)程開(kāi)始!");
  Callable<String> result = new Callable<String>() {
   @Override
   public String call() throws Exception {
    log.info("副線(xiàn)程開(kāi)始!");
    Thread.sleep(1000);
    log.info("副線(xiàn)程結(jié)束!");
    return "SUCCESS";
   }
  };
  log.info("主線(xiàn)程結(jié)束!");
  return result;
 }

輸出的結(jié)果如下:

主線(xiàn)程開(kāi)始!

主線(xiàn)程結(jié)束!

副線(xiàn)程開(kāi)始!

副線(xiàn)程結(jié)束!

主線(xiàn)程會(huì)提前返回,可以處理其他請(qǐng)求,等待有結(jié)果之后再輸出結(jié)果

DeferredResult

一旦啟用了異步請(qǐng)求處理功能 ,控制器就可以將返回值包裝在DeferredResult,控制器可以從不同的線(xiàn)程異步產(chǎn)生返回值。優(yōu)點(diǎn)就是可以實(shí)現(xiàn)兩個(gè)完全不相干的線(xiàn)程間的通信。

我們模擬如下場(chǎng)景:

由于消息隊(duì)列和應(yīng)用2的部分太繁瑣,我們使用一個(gè)類(lèi)來(lái)代替

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class MockQueue {
 private String placeOrder;
 private String completeOrder;
 private Logger logger = LoggerFactory.getLogger(getClass());
 public String getPlaceOrder() {
  return placeOrder;
 }
 public void setPlaceOrder(String placeOrder) throws Exception {
  new Thread(() -> {
   logger.info("接到下單請(qǐng)求, " + placeOrder);
   try {
    Thread.sleep(1000);
   } catch (Exception e) {
    e.printStackTrace();
   }
   this.completeOrder = placeOrder;
   logger.info("下單請(qǐng)求處理完畢," + placeOrder);
  }).start();
 }
 public String getCompleteOrder() {
  return completeOrder;
 }
 public void setCompleteOrder(String completeOrder) {
  this.completeOrder = completeOrder;
 }
}

定義一個(gè)Controller即線(xiàn)程1的部分

import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
@RestController
public class AsyncController {
 @Autowired
 private MockQueue mockQueue;
 @Autowired
 private DeferredResultHolder deferredResultHolder;
 private Logger logger = LoggerFactory.getLogger(getClass());
 @RequestMapping("/order")
 public DeferredResult<String> order() throws Exception {
  logger.info("主線(xiàn)程開(kāi)始");
  String orderNumber = RandomStringUtils.randomNumeric(8);
  mockQueue.setPlaceOrder(orderNumber);
  DeferredResult<String> result = new DeferredResult<>();
  deferredResultHolder.getMap().put(orderNumber, result);
  return result;
 }
}

定義一個(gè)類(lèi),用來(lái)線(xiàn)程1和線(xiàn)程2之間通信的,使用@Component默認(rèn)為單例,方便通信。

import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
@Component
public class DeferredResultHolder {
 private Map<String, DeferredResult<String>> map = new HashMap<String, DeferredResult<String>>();
 public Map<String, DeferredResult<String>> getMap() {
  return map;
 }
 public void setMap(Map<String, DeferredResult<String>> map) {
  this.map = map;
 }
}

定義一個(gè)類(lèi)來(lái)監(jiān)聽(tīng)訂單是否處理完,如果處理完了的話(huà)就設(shè)置deferredResultHolder中的DeferredResult的值,就會(huì)返回結(jié)果了。

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
 @Autowired
 private MockQueue mockQueue;
 @Autowired
 private DeferredResultHolder deferredResultHolder;
 private Logger logger = LoggerFactory.getLogger(getClass());
 @Override
 public void onApplicationEvent(ContextRefreshedEvent event) {
  new Thread(() -> {
   while (true) {
    if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
     String orderNumber = mockQueue.getCompleteOrder();
     logger.info("返回訂單處理結(jié)果:"+orderNumber);
     deferredResultHolder.getMap().get(orderNumber).setResult("place order success");
     mockQueue.setCompleteOrder(null);
    }else{
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   }
  }).start();
 }
}

補(bǔ)充:springmvc使用異步處理請(qǐng)求

同步請(qǐng)求圖示:

同步處理的圖示如上:HTTP請(qǐng)求,tomcat或其他中間件會(huì)有一個(gè)相應(yīng)的線(xiàn)程來(lái)處理這個(gè)Http請(qǐng)求,所有的業(yè)務(wù)邏輯都會(huì)在這個(gè)線(xiàn)程里去執(zhí)行,最后返回Http響應(yīng)。但是tomcat等中間件,它們可以管理的線(xiàn)程數(shù)是有限的,當(dāng)數(shù)量達(dá)到一定程度之后,再有請(qǐng)求進(jìn)入,會(huì)被阻塞掉。

簡(jiǎn)單異步圖示:

異步處理過(guò)程:當(dāng)一個(gè)http請(qǐng)求進(jìn)入后,tomcat等中間件的主線(xiàn)程調(diào)用副線(xiàn)程來(lái)執(zhí)行業(yè)務(wù)邏輯,當(dāng)副線(xiàn)程處理完成后,主線(xiàn)程再返回結(jié)果,在副線(xiàn)程處理整個(gè)業(yè)務(wù)邏輯的中,主線(xiàn)程會(huì)空閑出來(lái)去出來(lái)其他請(qǐng)求,也就是說(shuō)采用上述這種模式處理http請(qǐng)求,服務(wù)器的吞吐量會(huì)有有明顯的提升。使用異步返回,需使在web.xml將version配置為3.0版本的。

在servlet及所有的filter中配置異步支持。

簡(jiǎn)單實(shí)現(xiàn)如下:

更為復(fù)雜的業(yè)務(wù)場(chǎng)景的異步返回如下所示:

Htpp請(qǐng)求通過(guò)線(xiàn)程一處理,并將消息發(fā)送到消息隊(duì)列,應(yīng)用2處于不同的服務(wù)器,其接收到消息并將消息返回,線(xiàn)程2監(jiān)聽(tīng)到處理結(jié)果,將消息返回,線(xiàn)程一及線(xiàn)程二不知道對(duì)方的存在。這種業(yè)務(wù)情況,單開(kāi)一個(gè)線(xiàn)程是無(wú)法解決的,需要使用DeferredResult類(lèi)。

簡(jiǎn)單的實(shí)現(xiàn)代碼如下:

controller層:

@Controller
@RequestMapping("/test/")
@Slf4j
public class TestController {
 
 @Autowired
 private MockQueue mockQueue;
 
 @Autowired
 private DeferredResultHolder deferredResultHolder;
 
 @RequestMapping("order")
 @ResponseBody
 public DeferredResult<String> test() throws InterruptedException {
  log.info("主線(xiàn)程開(kāi)始");
  String orderNo = RandomUtils.nextInt() + "";
  mockQueue.setPlaceOrder(orderNo);
  DeferredResult<String> result = new DeferredResult<String>();
  deferredResultHolder.getMap().put(orderNo, result);
  log.info("主線(xiàn)程結(jié)束");
  return result;
 }
}

偽消息隊(duì)列類(lèi):

@Slf4j
@Component
public class MockQueue {
 
 private String placeOrder;
 
 private String compeleteOrder;
 
 public String getPlaceOrder() {
  return placeOrder;
 }
 
 public void setPlaceOrder(String placeOrder) throws InterruptedException {
  new Thread(()->{ log.info("收到下單的請(qǐng)求");
   this.placeOrder = placeOrder;
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
   this.compeleteOrder = placeOrder;
   log.info("完成下單的請(qǐng)求");}).start();
 
 }
 
 public String getCompeleteOrder() {
  return compeleteOrder;
 }
 
 public void setCompeleteOrder(String compeleteOrder) {
  this.compeleteOrder = compeleteOrder;
 }
}

偽隊(duì)列監(jiān)聽(tīng)類(lèi):

@Slf4j
@Component
public class QueueListener implements ApplicationListener{
 @Autowired
 private MockQueue mockQueue;
 @Autowired
 private DeferredResultHolder deferredResultHolder;
 
 @Override
 public void onApplicationEvent(ApplicationEvent applicationEvent) {
  new Thread(() ->{
   while (true){
    if(StringUtils.isNotBlank(mockQueue.getCompeleteOrder())){
     String orderNum = mockQueue.getCompeleteOrder();
     log.info("返回訂單處理結(jié)果" + orderNum);
     deferredResultHolder.getMap().get(orderNum).setResult("success");
     mockQueue.setCompeleteOrder(null);
    }else {
     try {
      Thread.sleep(100);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }
   }
  }).start();
 }
}

容器類(lèi):

@Component
public class DeferredResultHolder {
 private Map<String,DeferredResult<String>> map = new HashMap<String,DeferredResult<String>>();
 
 public Map<String, DeferredResult<String>> getMap() {
  return map;
 }
 
 public void setMap(Map<String, DeferredResult<String>> map) {
  this.map = map;
 }
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

相關(guān)文章

  • Java開(kāi)發(fā)HashMap?key必須實(shí)現(xiàn)hashCode?equals方法原理

    Java開(kāi)發(fā)HashMap?key必須實(shí)現(xiàn)hashCode?equals方法原理

    這篇文章主要為大家介紹了Java開(kāi)發(fā)HashMap?key必須實(shí)現(xiàn)hashCode?equals方法原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • SpringBoot導(dǎo)入Druid運(yùn)行失敗問(wèn)題

    SpringBoot導(dǎo)入Druid運(yùn)行失敗問(wèn)題

    這篇文章主要介紹了SpringBoot導(dǎo)入Druid運(yùn)行失敗,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Flask實(shí)現(xiàn)異步非阻塞請(qǐng)求功能實(shí)例解析

    Flask實(shí)現(xiàn)異步非阻塞請(qǐng)求功能實(shí)例解析

    這篇文章主要介紹了Flask實(shí)現(xiàn)異步非阻塞請(qǐng)求功能實(shí)例解析,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • 如何使用Collections.reverse對(duì)list集合進(jìn)行降序排序

    如何使用Collections.reverse對(duì)list集合進(jìn)行降序排序

    這篇文章主要介紹了Java使用Collections.reverse對(duì)list集合進(jìn)行降序排序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • SpringBoot使用Redisson實(shí)現(xiàn)延遲執(zhí)行的完整示例

    SpringBoot使用Redisson實(shí)現(xiàn)延遲執(zhí)行的完整示例

    這篇文章主要介紹了SpringBoot使用Redisson實(shí)現(xiàn)延遲執(zhí)行的完整示例,文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-06-06
  • 淺析JAVA 循環(huán)結(jié)構(gòu)

    淺析JAVA 循環(huán)結(jié)構(gòu)

    這篇文章主要介紹了JAVA 循環(huán)結(jié)構(gòu)的相關(guān)資料,文中講解的非常細(xì)致,示例代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 總結(jié)Java對(duì)象被序列化的兩種方法

    總結(jié)Java對(duì)象被序列化的兩種方法

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java對(duì)象被序列化的兩種方法展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 詳解Java中多進(jìn)程編程的實(shí)現(xiàn)

    詳解Java中多進(jìn)程編程的實(shí)現(xiàn)

    這篇文章主要介紹了詳解Java中多進(jìn)程編程的實(shí)現(xiàn),和多線(xiàn)程一樣,多進(jìn)程同樣是實(shí)現(xiàn)并發(fā)的一種方式,需要的朋友可以參考下
    2015-11-11
  • Java異常處理UncaughtExceptionHandler使用實(shí)例代碼詳解

    Java異常處理UncaughtExceptionHandler使用實(shí)例代碼詳解

    當(dāng)一個(gè)線(xiàn)程由于未捕獲異常即將終止時(shí),Java虛擬機(jī)將使用thread . getuncaughtexceptionhandler()查詢(xún)線(xiàn)程的uncaughtException處理程序,并調(diào)用處理程序的uncaughtException方法,將線(xiàn)程和異常作為參數(shù)傳遞
    2023-03-03
  • Java多線(xiàn)程中的Future類(lèi)詳細(xì)解讀

    Java多線(xiàn)程中的Future類(lèi)詳細(xì)解讀

    這篇文章主要介紹了Java多線(xiàn)程中的Future類(lèi)詳細(xì)解讀,Future表示一個(gè)可能還沒(méi)有完成的異步任務(wù)的結(jié)果,針對(duì)這個(gè)結(jié)果可以添加Callback以便在任務(wù)執(zhí)行成功或失敗后作出相應(yīng)的操作,需要的朋友可以參考下
    2023-11-11

最新評(píng)論

泰来县| 镇平县| 开封县| 于田县| 鞍山市| 绍兴市| 康保县| 闻喜县| 金溪县| 敖汉旗| 大同市| 镇安县| 饶河县| 镇巴县| 公主岭市| 茌平县| 阿拉善右旗| 朔州市| 大同县| 长乐市| 贺兰县| 临颍县| 仁怀市| 太仆寺旗| 甘泉县| 舞阳县| 白山市| 大城县| 鄄城县| 孟津县| 扬中市| 青神县| 布拖县| 东辽县| 枞阳县| 克什克腾旗| 济宁市| 海原县| 柘城县| 金寨县| 达孜县|