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 1075 What Are You Talking About 字典树模板

    What Are You Talking About Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/204800 K ...

  2. Redis ,Memcached ,Mongodb 对比

    memcached: 1.适合做内存缓存,对可靠性没有要求,不支持持久化:速度快.并发高.2.支持的数据结构单一,只支持Key-value,3.value最大支持1M3.在传统tomcat 部署war ...

  3. drupal 开发笔记

    “以前我在开发Java项目的时候,都需要自己设计数据库表结构,数据库表结构的设计关系到一个人开发技能的高低,而在Drupal里面,我们通常是不需要设计数据库表结构,我们要做的是创建新的内容类型,然后为 ...

  4. 【JavaScript】闭包应用之数据缓存

    最近的开发中的许多事件会被频繁的触发,由于没有做缓存的处理,每次事件触发都会后台调用一样的数据.这几天我突然意识到自己的代码有很大的优化空间,继而想起了闭包可以有缓存的功能,于是乎便对其进行了深入的研 ...

  5. CSS background 属性详解

    CSS background Property 语法: background: bg-color bg-image position/bg-size bg-repeat bg-origin bg-cl ...

  6. css预处理器(sass)

    学过CSS的人都知道,它不是一种编程语言.你可以用它开发网页样式,但是没法用它编程.也就是说,CSS基本上是设计师的工具,不是程序员的工具.在程序员眼里,CSS是一件很麻烦的东西.它没有变量,也没有条 ...

  7. vuex(数据商店实现思想)day06

    安装创建Vue项目

  8. windows 下 openssl 生成RSA私钥公钥以及PKCS8

    生成RSA私钥 打开bin文件夹下面的openssl.exe,输入genrsa -out rsa_private_key.pem 1024 把RSA私钥转换成PKCS8格式 输入命令pkcs8 -to ...

  9. mysql在linux下的安装mysql-5.6.33

    一.下载源码包 wget http://mirrors.sohu.com/mysql/MySQL-5.6/mysql-5.6.35-linux-glibc2.5-x86_64.tar.gz 二.解压源 ...

  10. Python学习---django多对多之Djanog默认表学习

    案例一: from django.db import models class Book(models.Model): name = models.CharField(max_length=33) # ...