如何异步的处理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服务接口. 二.搭建基础 ...
 
随机推荐
- CakePHP调用model类和foreach循环
			
1. 引入Model类 2.调用model类(Guarantee)下的getCity()方法 3.写sql语句 并返回获得值 4.foreach循环取得的城市
 - Mac(OS X)中Git安装与GitHub基本使用
			
GitHub是一个面向开源及私有软件项目的托管平台.开源代码库以及版本控制系统,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub.通常在Windows下使用GitHub的教程是非常 ...
 - 1142 奖学金  sort做法
			
个人博客:doubleq.win 1142 奖学金 2007年NOIP全国联赛普及组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 题目 ...
 - CentOS网卡显示为__tmpxxxxxxxx
			
一台服务器做了2组端口绑定(bonding),其中一组bond总是不成功,发现少了eth0/eth5 两个网卡,后来通过ifconfig -a 发现多了两个__tmpxxx的网卡 ifconfig - ...
 - 控制HTML页面内容不能选中的方法
			
方法有二 一: css 方法 user-seletct: none;-webkit-user-seletct: none;-moz-user-seletct: none;-ms-user-seletc ...
 - xml-treeview转换
			
XML——>treeciew using System; using System.Collections.Generic; using System.Text; using System.Wi ...
 - Linux运维体系
 - LeetCode5 最长回文子串
			
最长回文子串 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad" 输出: "bab" ...
 - asp.net生成PDF文件参考 .
			
TextSharp 是用来生成 PDF 的一个组件,在 1998 年夏天的时候,Bruno Lowagie ,iText 的创作者,参与了学校的一个项目,当时使用 HTML 来生成报告,但是,使用 ...
 - POP动画[3]
			
POP动画[3] 这一节主要讲解POP动画的自定义动画属性. POP动画中有一个参数,叫timingFunction,与CoreAnimation中的一个参数CAMediaTimingFunction ...