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