如何异步的处理restful服务(基础)
生活随笔
收集整理的這篇文章主要介紹了
如何异步的处理restful服务(基础)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
如何異步的處理restful服務(基礎)
1、使用Runnable
2、使用DeferredResult
3、異步處理的一些配置
?
?
正常請求方式
package com.nxz.controller;import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.Callable;/*** 異步處理的controller*/ @RestController @Slf4j public class AsyncController {//標準的同步處理邏輯@RequestMapping("/order")public String order() throws InterruptedException {log.info("主線城開始");Thread.sleep(1000);//具體的業務邏輯log.info("主線程返回");return "success";}}?
1、通過callable異步方式
package com.nxz.controller;import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.Callable;/*** 異步處理的controller*/ @RestController @Slf4j public class AsyncController {//異步處理方式@RequestMapping("/order1")public Callable<String> order1() throws InterruptedException {log.info("主線城開始");Callable<String> callable = new Callable<String>() {@Overridepublic String call() throws Exception {log.info("副線程線程開始 callable.call()");Thread.sleep(1000);//具體的業務邏輯log.info("副線程線程結束 callable.call()");return "success";}};log.info("主線程返回");return callable;}}訪問order1后日志輸出:日志表明主線程返回就代表請求已經結束,但是具體的數據信息是在副線程結束時
才返回的(也就是在主線程結束后tomcat等中間件是可以接受其他http請求,增大了吞吐量)
2019-04-29 20:28:32.433 INFO 16788 --- [nio-8080-exec-4] com.nxz.controller.AsyncController : 主線城開始 2019-04-29 20:28:32.434 INFO 16788 --- [nio-8080-exec-4] com.nxz.controller.AsyncController : 主線程返回 2019-04-29 20:28:32.434 INFO 16788 --- [ MvcAsync2] com.nxz.controller.AsyncController : 副線程線程開始 callable.call() 2019-04-29 20:28:33.435 INFO 16788 --- [ MvcAsync2] com.nxz.controller.AsyncController : 副線程線程結束 callable.call()瀏覽器顯示結果時間??
?
?
2、DeferredResult形式
runnable形式的缺點:副線程的發起必須是在主線程下,但是企業級開發時,是比較復雜的。
DeferredResult是在應用1接受http請求后,由線程1將請求放到消息隊列中,然后又另一臺服務器具體啟用副線程執行邏輯,處理完成之后由線程二監聽消息隊列,接受返回數據,返回給前端
controller:
@Autowiredprivate MockQueue mockQueue;@Autowiredprivate DeferredResultHolder deferredResultHolder;//在主線程中是看不到副線程的任何東西的@RequestMapping("/order2")public DeferredResult<String> order2() throws InterruptedException {log.info("主線程開始");String orderNum = RandomStringUtils.randomNumeric(8);//模擬訂單號mockQueue.setPlaceOrder(orderNum);//模擬消息隊列(將訂單號放到消息隊里中)DeferredResult<String> result = new DeferredResult<>();deferredResultHolder.getMap().put(orderNum, result);log.info("主線程結束");return result;}模擬隊列:
package com.nxz.async;import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component;/*** 模擬隊列的對象*/@Getter @Component @Slf4j public class MockQueue {//代表接受的信息private String placeOrder;//代表返回的消息private String complateOrder;//set 方法模擬往消息隊列中放消息public void setPlaceOrder(String placeOrder) throws InterruptedException {new Thread(() -> {log.info("接到請求消息" + placeOrder);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}this.complateOrder = placeOrder;log.info("接到請求消息處理完成" + placeOrder);}).start();}public void setComplateOrder(String complateOrder) {this.complateOrder = complateOrder;} }?
異步監聽處理結果:
package com.nxz.async;import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.stereotype.Component;//監聽器 @Component @Slf4j public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {@Autowiredprivate MockQueue mockQueue;@Autowiredprivate DeferredResultHolder deferredResultHolder;/*** ContextRefreshedEvent這個事件是spring初始化完畢的一個事件* 監聽這個事件就是為了 在系統啟動完畢后要做什么事** @param contextRefreshedEvent*/@Overridepublic void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {log.info("接受返回結果的listener");new Thread(() -> {//將以下while循環放到一個單開的thred線程 防止主線程死循環//監聽mockqueue中的complateOrderwhile (true) {if (StringUtils.isNotBlank(mockQueue.getComplateOrder())) {String orderNum = mockQueue.getComplateOrder();//返回訂單處理結果log.info("返回訂單處理結果" + orderNum);deferredResultHolder.getMap().get(orderNum).setResult("place order success");mockQueue.setComplateOrder(null);//表名任務已經處理完了} else {//complateorder中沒有值是睡眠100毫秒try {log.info("沒有任務休眠100毫秒");Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}}).start();} }?
?發送一個請求后,日志輸出:
2019-04-29 21:27:18.959 INFO 7176 --- [nio-8080-exec-3] com.nxz.controller.AsyncController : 主線程開始 2019-04-29 21:27:18.960 INFO 7176 --- [nio-8080-exec-3] com.nxz.controller.AsyncController : 主線程結束 2019-04-29 21:27:18.960 INFO 7176 --- [ Thread-43] com.nxz.async.MockQueue : 接到請求消息76311604 2019-04-29 21:27:19.961 INFO 7176 --- [ Thread-43] com.nxz.async.MockQueue : 接到請求消息處理完成76311604 2019-04-29 21:27:21.242 INFO 7176 --- [ Thread-30] com.nxz.async.QueueListener : 返回訂單處理結果76311604?
?
?
posted @ 2019-04-29 22:29 巡山小妖N 閱讀(...) 評論(...) 編輯 收藏總結
以上是生活随笔為你收集整理的如何异步的处理restful服务(基础)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: restful api上传文件(基础)-
- 下一篇: wireMock快速伪造restful服