java异步处理rest服务_如何异步的处理restful服务(基础)

本文介绍了两种Java中实现REST服务异步处理的方法:使用Callable和DeferredResult。Callable允许主线程返回后,副线程继续执行业务逻辑,提高系统吞吐量。而DeferredResult则模拟了消息队列的处理方式,主线程不等待副线程执行,由单独线程监听并返回结果给前端,适合复杂的企业级开发场景。
摘要由CSDN通过智能技术生成

1、使用Runnable

2、使用DeferredResult

3、异步处理的一些配置

aa26cbf037c047e09c9f651e902e9453.png

正常请求方式

packagecom.nxz.controller;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.concurrent.Callable;/*** 异步处理的controller*/@RestController

@Slf4jpublic classAsyncController {//标准的同步处理逻辑

@RequestMapping("/order")public String order() throwsInterruptedException {

log.info("主线城开始");

Thread.sleep(1000);//具体的业务逻辑

log.info("主线程返回");return "success";

}

}

1、通过callable异步方式

packagecom.nxz.controller;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.util.concurrent.Callable;/*** 异步处理的controller*/@RestController

@Slf4jpublic classAsyncController {//异步处理方式

@RequestMapping("/order1")public Callable order1() throwsInterruptedException {

log.info("主线城开始");

Callable callable = new Callable() {

@Overridepublic String call() throwsException {

log.info("副线程线程开始 callable.call()");

Thread.sleep(1000);//具体的业务逻辑

log.info("副线程线程结束 callable.call()");return "success";

}

};

log.info("主线程返回");returncallable;

}

}

访问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()

浏览器显示结果时间

d1185c1c67d82bdad10b0a0d5c3c5dc0.png

2、DeferredResult形式

runnable形式的缺点:副线程的发起必须是在主线程下,但是企业级开发时,是比较复杂的。

DeferredResult是在应用1接受http请求后,由线程1将请求放到消息队列中,然后又另一台服务器具体启用副线程执行逻辑,处理完成之后由线程二监听消息队列,接受返回数据,返回给前端

a3050fd44ca0b8bdc17e8ff5641a929d.png

controller:

@AutowiredprivateMockQueue mockQueue;

@AutowiredprivateDeferredResultHolder deferredResultHolder;//在主线程中是看不到副线程的任何东西的

@RequestMapping("/order2")public DeferredResult order2() throwsInterruptedException {

log.info("主线程开始");

String orderNum= RandomStringUtils.randomNumeric(8);//模拟订单号

mockQueue.setPlaceOrder(orderNum);//模拟消息队列(将订单号放到消息队里中)

DeferredResult result = new DeferredResult<>();

deferredResultHolder.getMap().put(orderNum, result);

log.info("主线程结束");returnresult;

}

模拟队列:

packagecom.nxz.async;importlombok.Getter;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;/*** 模拟队列的对象*/@Getter

@Component

@Slf4jpublic classMockQueue {//代表接受的信息

privateString placeOrder;//代表返回的消息

privateString complateOrder;//set 方法模拟往消息队列中放消息

public void setPlaceOrder(String placeOrder) throwsInterruptedException {new Thread(() ->{

log.info("接到请求消息" +placeOrder);try{

Thread.sleep(1000);

}catch(InterruptedException e) {

e.printStackTrace();

}this.complateOrder =placeOrder;

log.info("接到请求消息处理完成" +placeOrder);

}).start();

}public voidsetComplateOrder(String complateOrder) {this.complateOrder =complateOrder;

}

}

异步监听处理结果:

packagecom.nxz.async;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.lang.StringUtils;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.ApplicationListener;importorg.springframework.context.event.ContextRefreshedEvent;importorg.springframework.stereotype.Component;//监听器

@Component

@Slf4jpublic class QueueListener implements ApplicationListener{

@AutowiredprivateMockQueue mockQueue;

@AutowiredprivateDeferredResultHolder deferredResultHolder;/*** ContextRefreshedEvent这个事件是spring初始化完毕的一个事件

* 监听这个事件就是为了 在系统启动完毕后要做什么事

*

*@paramcontextRefreshedEvent*/@Overridepublic voidonApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {

log.info("接受返回结果的listener");new Thread(() ->{//将以下while循环放到一个单开的thred线程 防止主线程死循环//监听mockqueue中的complateOrder

while (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 : 接到请求消息763116042019-04-29 21:27:19.961 INFO 7176 --- [ Thread-43] com.nxz.async.MockQueue : 接到请求消息处理完成763116042019-04-29 21:27:21.242 INFO 7176 --- [ Thread-30] com.nxz.async.QueueListener : 返回订单处理结果76311604

c53bcbd434eb0056b252089f5029710e.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值