如何异步的处理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>() { @Override
public 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:
@Autowired
private MockQueue mockQueue; @Autowired
private 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> { @Autowired
private MockQueue mockQueue; @Autowired
private DeferredResultHolder deferredResultHolder; /**
* ContextRefreshedEvent这个事件是spring初始化完毕的一个事件
* 监听这个事件就是为了 在系统启动完毕后要做什么事
*
* @param contextRefreshedEvent
*/
@Override
public void onApplicationEvent(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 : 接到请求消息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
如何异步的处理restful服务(基础)的更多相关文章
- java 利用JAX-RS快速开发RESTful 服务
JAX-RS(Java API for RESTful Web Services)同样也是JSR的一部分,详细规范定义见 https://jcp.org/en/jsr/detail?id=311 .从 ...
- atitit.RESTful服务的概览and框架选型
atitit.RESTful服务的概览and框架选型 1. REST基础概念: 1 2. URL说明: 1 3. 1 4. RESTful框架选型 2 1. spring mvc( recomm) ...
- 应用Spring MVC发布restful服务是怎样的一种体验
摘要:“约定优于配置”这是一个相当棒的经验,SOAP服务性能差.基于配置.紧耦合,restful服务性能好.基于约定.松耦合,现在我就把使用Spring MVC发布restful服务的 ...
- 使用多种客户端消费WCF RestFul服务(四)——Jquery篇
Jquery篇 互联网开发中少不了各类前端开发框架,其中JQUERY就是最流行之一,本篇我们就采用JQUERY来消费WCF RestFul服务,其中用到JSON基础知识,如果有想了解的朋友,请访问:& ...
- java_java 利用JAX-RS快速开发RESTful 服务
JAX-RS(Java API for RESTful Web Services)同样也是JSR的一部分,详细规范定义见 https://jcp.org/en/jsr/detail?id=311 .从 ...
- RESTful 服务架构风格 * .NET的RESTful框架 OpenRasta
REST 的约束采用的就是掌控 Web 的基本原则.这些原则是: 用户代理与资源交互,任何可命名和表达的事物都可称为资源.每项资源都有一个唯一的统一资源标识符 (URI). 与资源的交互(通过其唯一的 ...
- 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持
HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...
- RESTful服务最佳实践
本文主要读者 引言 REST是什么 统一接口 基于资源 通过表征来操作资源 自描述的信息 超媒体即应用状态引擎(HATEOAS) 无状态 可缓存 C-S架构 分层系统 按需编码(可选) REST快速提 ...
- Spring Boot初探之restful服务发布
一.背景 Spring boot是集服务发布.数据库管理.日志管理等于一身的服务开发框架:是微服务开发的全能小帮手.这章讲述一下如何使用spring boot发布restful服务接口. 二.搭建基础 ...
随机推荐
- eclipse中编写运行c/c++
注意:此过程有点复杂 准备:1.MinGW:c/c++运行环境: 2.CDT 1.MinGW:安装程序:http://sourceforge.net/projects/mingw/?source=ty ...
- Python Django ORM基本增删改查
工程下的urls.py中增加如下: from cmdb import views as cmdb #要把你要操作的项目import进来 urlpatterns = [ url(r'orm', cmdb ...
- JS 处理浮点型问题
function disposeNumber(value){ if(value == null || value == ""){ return 0; }else if(value. ...
- COCI2017-2018-2 San
题意 有\(n \leq 40\)个节点,每个节点有权值\(H \leq 1e9\)和贡献\(v \leq 1e9\),从任意一个点可以向右跳到一个权值不小于它的节点,并获得该点贡献 可以从任意一个点 ...
- 有标号的DAG计数系列问题
传送门 II 设 \(f_i\) 表示 \(i\) 个点的答案 那么枚举至少 \(j\) 个点的出度为 \(0\) \[\sum_{j=0}^{i}(-1)^j\binom{i}{j}f_{i-j}2 ...
- js图片跟随鼠标移动
<div id="wrapper"><img src="http://images.cnblogs.com/cnblogs_com/rain-null/ ...
- win7 远程连接服务器出现身份验证错误,且找不到加密Oracle修正
用远程桌面连接登录服务器,结果,弹出一个错误的提示框:发生身份验证错误,要求的函数不受支持. 然后在网上找了相关的教程,基本上所有的方法都是如下所示: 策略路径:"计算机配置"-& ...
- sql查询学习和实践点滴积累
https://blog.rjmetrics.com/2008/10/28/correlated-subqueries-in-mysql/ http://www.mysqltutorial.org/m ...
- 从golang-gin-realworld-example-app项目学写httpapi (二)
https://github.com/gothinkster/golang-gin-realworld-example-app/blob/master/users/models.go 模型定义 use ...
- Java代码调用存储过程和存储方法
准备一个oracle 的JDBC jar 包:ojdbc14_11g.jar 首先找到你的 oracle 安装位置,例如: 1.创建一个JDBC数据库连接工具类: package com.test.d ...