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服务(基础)的更多相关文章

  1. java 利用JAX-RS快速开发RESTful 服务

    JAX-RS(Java API for RESTful Web Services)同样也是JSR的一部分,详细规范定义见 https://jcp.org/en/jsr/detail?id=311 .从 ...

  2. atitit.RESTful服务的概览and框架选型

    atitit.RESTful服务的概览and框架选型 1. REST基础概念: 1 2. URL说明: 1 3.  1 4. RESTful框架选型 2 1. spring mvc( recomm) ...

  3. 应用Spring MVC发布restful服务是怎样的一种体验

            摘要:“约定优于配置”这是一个相当棒的经验,SOAP服务性能差.基于配置.紧耦合,restful服务性能好.基于约定.松耦合,现在我就把使用Spring MVC发布restful服务的 ...

  4. 使用多种客户端消费WCF RestFul服务(四)——Jquery篇

    Jquery篇 互联网开发中少不了各类前端开发框架,其中JQUERY就是最流行之一,本篇我们就采用JQUERY来消费WCF RestFul服务,其中用到JSON基础知识,如果有想了解的朋友,请访问:& ...

  5. java_java 利用JAX-RS快速开发RESTful 服务

    JAX-RS(Java API for RESTful Web Services)同样也是JSR的一部分,详细规范定义见 https://jcp.org/en/jsr/detail?id=311 .从 ...

  6. RESTful 服务架构风格 * .NET的RESTful框架 OpenRasta

    REST 的约束采用的就是掌控 Web 的基本原则.这些原则是: 用户代理与资源交互,任何可命名和表达的事物都可称为资源.每项资源都有一个唯一的统一资源标识符 (URI). 与资源的交互(通过其唯一的 ...

  7. 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持

    HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...

  8. RESTful服务最佳实践

    本文主要读者 引言 REST是什么 统一接口 基于资源 通过表征来操作资源 自描述的信息 超媒体即应用状态引擎(HATEOAS) 无状态 可缓存 C-S架构 分层系统 按需编码(可选) REST快速提 ...

  9. Spring Boot初探之restful服务发布

    一.背景 Spring boot是集服务发布.数据库管理.日志管理等于一身的服务开发框架:是微服务开发的全能小帮手.这章讲述一下如何使用spring boot发布restful服务接口. 二.搭建基础 ...

随机推荐

  1. HDU 2578(二分查找)

    686MS #include <iostream> #include <cstdlib> #include <cstdio> #include <algori ...

  2. 记录LNMP环境彻底删除绑定域名及网站文件夹/文件的过程

    lnmp vhost del #删除绑定的域名 chattr -i /home/wwwroot/域名文件夹/.user.ini #解除文件安全限制 rm -rf /home/wwwroot/域名文件夹 ...

  3. Canvas中的剪切clip()方法

    Canvas中的剪切 接下来我们要聊的不是图像的合成,而是Canvas中的另一个有用的功能:剪切区域.它是Canvas之中由路径所定义的一块区域,浏览器会将所有的绘图操作都限制在本区域内执行.在默认情 ...

  4. JQuery 判断指定ID是否存在

  5. 【javascript】javascript设计模式之单例模式

    单例模式: 定义:单例模式之所以这么叫,是因为它限制一个类只能有一个实例化对象. 实现方法:判断实例是否存在,如果存在则直接返回,如果不存在就创建了再返回.(确保一个类只有一个实例对象) 特点: 命名 ...

  6. centos虚拟机下安装nginx

    通过yum安装 yum install epel-release -y(企业级的镜像源) yum install nginx-y 启动.停止.重启 service nginx start servic ...

  7. ElasticSearch初体验之使用

    好久没写博文了, 最近项目中使用到了ElaticSearch相关的一些内容, 刚好自己也来做个总结.现在自己也只能算得上入门, 总结下自己在工作中使用Java操作ES的一些小经验吧. 本文总共分为三个 ...

  8. SSH 无法启动的原因分析及解决方法

    简介 Secure Shell(缩写为 SSH),由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为一项创建在应用层和传输层基础上的安全协议,为计算机上的 S ...

  9. 卸载Sharepoint2016后。重新安装提示 系统从以前的安装重新启动,或更新正在等待错误

    卸载Sharepoint2016 重启N遍,不停地重启.需要删除注册表项 下的 .将PendingFileRenameOperations键项删除,再重新安装就可以安装成功.

  10. ubuntu13.04更新源

    最近163的源出问题了,又要换一次源. 报错如下: 查更新源的命令查了好多次,这次还是记下来吧,估计以后还会用到很多次. 常规来说,是要先备份的,不过感觉备份也没什么用,所以就直接跳过吧.. 1  打 ...