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. DLL文件

    Dll文件的全称是Dynamic Link Library,中文意思为动态链接库,DLL文件是不可执行文件,其是一个包含由多个程序同时使用的代码和数据的库,动态链接提供了一种方法,使进程可以调用不属于 ...

  2. Chromium base库分割字符串SplitString

    前一段时间在工作过程中遇到一个场景需要将http response中的request header中的cookie字段取出并进行解析,但是手头没有解析cookie的工具类,同时cookie的表现就是个 ...

  3. 【设计模式】observer(观察者)-- 对象行为型模式5.7

    1.意图 对象之间一对多的依赖关系,当目标对象发生改变时,所有依赖于它的对象都要得到通知并自动更新 2.别名 依赖,发布-订阅 3.动机 1)需要确保相互协作的对象的一致性(数据要保持一致),但一致性 ...

  4. Vue组件通讯

    Vue最常用的组件通讯有三种:父->子组件通讯.子->父组件通讯,兄弟组件通讯.(template用的pug模板语法) 1.父->子组件通讯 父->子组件通讯,是通过props ...

  5. 前端把html表格生成为excel表格

    最近公司改后台管理系统.要求导出台账项目等等为excel表格,找半天还真有,他是通过query.table2excel.js 实现,原谅我原生不会弄这个当然大家有可以给我留言. <!DOCTYP ...

  6. Telnet初试(本地测试)

    win7下开启Telnet功能: 控制面板-程序和功能- 开启服务 然后回车 这样即可完成一次请求

  7. 理解JMeter聚合报告(Aggregate Report)

    Aggregate Report 是 JMeter 常用的一个 Listener,中文被翻译为“聚合报告”.今天再次有同行问到这个报告中的各项数据表示什么意思,顺便在这里公布一下,以备大家查阅. 如果 ...

  8. 软工读书笔记 week3 (《黑客与画家》上)

    一.何谓黑客? 黑客,在我们大多数普通人眼里,就是入侵计算机的人,通常还与干坏事挂钩.而书中告诉我们,这 并不是它的真正含义.而要想理解这本书,就要首先理解什么是黑客. 黑客这个词最初起源时,完全是一 ...

  9. Android知识点滴

    今天,把新作的布局状态魅族机上进行测试 发现了一个BUG,造成闪退. 看了下log,一个布局造成的. 开始分析这个布局造成这个问题的原因. 开始艰难的调试过程. 代码注释大法,发现这个问题是一个tex ...

  10. Lua 5.3 参考手册

    转自:http://www.runoob.com/manual/lua53doc/manual.html 1 – 简介 Lua 是一门扩展式程序设计语言,被设计成支持通用过程式编程,并有相关数据描述设 ...