呼叫我或异步REST
本文是使用Spring Boot + Java 8创建的工作正常的异步REST应用程序的非常简单的示例。SpringBoot使得开发Web应用程序几乎非常容易,但是为了简化任务,我从Spring存储库中举了一个例子,称为rest- service ,将其分叉到我自己的存储库中 ,并出于我的目的对其进行了更改,以创建两个应用程序:客户端和服务器。
我们的服务器应用程序将是一个简单的REST Web服务,它将查询GitHub以获取一些用户数据并将其返回。 我们的客户端应用程序还将是REST Web服务……将查询第一个应用程序!
服务器代码基本上由服务和控制器组成。 该服务使用带有@Async批注的异步方法,如下所示。
@Service
public class GitHubLookupService {private static final Logger logger = LoggerFactory.getLogger(GitHubLookupService.class);private final RestTemplate restTemplate;public GitHubLookupService(RestTemplateBuilder restTemplateBuilder) {this.restTemplate = restTemplateBuilder.build();}@AsyncCompletableFuture<User> findUser(String user) throws InterruptedException {logger.info("Looking up " + user);String url = String.format("https://api.github.com/users/%s", user);User results = restTemplate.getForObject(url, User.class);// Artificial delay of 1s for demonstration purposesThread.sleep(1000L);return CompletableFuture.completedFuture(results);}}
服务器控制器:
@RestController
public class GitHubController {private final GitHubLookupService lookupService;@Autowiredpublic GitHubController(GitHubLookupService lookupService) {this.lookupService = lookupService;}@RequestMapping("/user/{name}")public CompletableFuture<TimedResponse<User>> findUser(@PathVariable(value = "name") String name) throws InterruptedException, ExecutionException {long start = System.currentTimeMillis();ServerResponse response = new ServerResponse(Thread.currentThread().getName());return lookupService.findUser(name).thenApply(user -> {response.setData(user);response.setTimeMs(System.currentTimeMillis() - start);response.setCompletingThread(Thread.currentThread().getName());return response;});}}
我们这里拥有的是来自Java 8的简单CompletableFuture ,借助thenApply()我们将其转换为所需的格式,该格式允许我们添加有关当前线程的一些数据,以确保执行确实是异步发生的,也就是说,完成工作的线程不是开始工作的线程。 我们可以确定这一点,运行应用程序并检查调用结果:
marina@Marinas-MacBook-Pro:~$ http http://localhost:8080/user/mchernyavskaya
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Date: Mon, 02 Oct 2017 18:07:54 GMT
Transfer-Encoding: chunked{"completingThread": "SimpleAsyncTaskExecutor-1","data": {"avatar_url": "https://avatars2.githubusercontent.com/u/538843?v=4","company": "OLX","location": "Berlin, Germany","name": "Maryna Cherniavska","url": "https://api.github.com/users/mchernyavskaya"},"error": false,"startingThread": "http-nio-8080-exec-1","timeMs": 2002
}
现在,我们需要创建一个将调用服务器应用程序的客户端应用 程序 。 在Spring中有一个非常方便的用于使用REST的类,称为RestTemplate 。 但是,RestTemplate是同步的,我们在服务器应用程序中进行的所有不错的异步处理对客户端应用程序完全没有帮助。 这两个应用程序是完全独立的。 客户端应用程序只知道它将处理一个相当长时间的调用。 由于客户端应用程序知道这一点,并且由于它可能不想在服务器应用程序查询的整个过程中都占用线程,因此我们也将使其异步。 AsyncRestTemplate即将解救!
我们的客户端应用程序将更加简单,并将主要由控制器代码组成 。 要在一台本地计算机上运行两个应用程序,我们需要使用-Dserver.port = 8082参数更改服务器的端口。 因此,我们的服务器现在位于localhost:8080上,客户端位于localhost:8082上。
客户端控制器主要如下。
@RestController
public class GitHubController {private static final String BASE_URL = "http://localhost:8080/";private final AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();@RequestMapping("/async/user/{name}")public ListenableFuture<ClientResponse> findUserAsync(@PathVariable(value = "name") String name)throws InterruptedException, ExecutionException {long start = System.currentTimeMillis();ClientResponse clientResponse = new ClientResponse(Thread.currentThread().getName());ListenableFuture<ResponseEntity<ServerResponse>> entity = asyncRestTemplate.getForEntity(BASE_URL + name, ServerResponse.class);entity.addCallback(new ListenableFutureCallback<ResponseEntity<ServerResponse>>() {@Overridepublic void onFailure(Throwable ex) {clientResponse.setError(true);clientResponse.setCompletingThread(Thread.currentThread().getName());clientResponse.setTimeMs(System.currentTimeMillis() - start);}@Overridepublic void onSuccess(ResponseEntity<ServerResponse> result) {clientResponse.setData(result.getBody());clientResponse.setCompletingThread(Thread.currentThread().getName());clientResponse.setTimeMs(System.currentTimeMillis() - start);}});}
}
我们正在获取服务器响应,并将其包装到有关时序和当前线程的更多数据中,以便更好地了解发生了什么。 AsyncRestTemplate提供了一个ListenableFuture ,但是我们用它完成了一个CompletableFuture ,因为它允许我们手动控制未来返回的时刻,并在此过程中转换输出。
当我们调用客户服务时,它返回以下数据:
marina@Marinas-MacBook-Pro:~$ http http://localhost:8082/async/user/mchernyavskaya
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Date: Mon, 02 Oct 2017 18:28:36 GMT
Transfer-Encoding: chunked{"completingThread": "SimpleAsyncTaskExecutor-1","data": {"completingThread": "SimpleAsyncTaskExecutor-3","data": {"avatar_url": "https://avatars2.githubusercontent.com/u/538843?v=4","company": "OLX","location": "Berlin, Germany","name": "Maryna Cherniavska","url": "https://api.github.com/users/mchernyavskaya"},"error": false,"startingThread": "http-nio-8080-exec-7","timeMs": 1403},"error": false,"startingThread": "http-nio-8082-exec-3","timeMs": 1418
}
您可以在此处阅读有关Spring中异步方法的更多信息,但是这个简单的示例应该可以帮助您了解事物的工作方式。 完整的代码在存储库中 。 希望它有一定用处!
翻译自: https://www.javacodegeeks.com/2017/10/call-asynchronous-rest.html
呼叫我或异步REST相关推荐
- 【转】无服务计算(Serverless Computing)核心知识
Serverless Computing概念 云原生计算基金会CNCF(Cloud Native Computing Foundation, CNCF)Serverless Whitepaper v1 ...
- 使用网络模拟器 Packet Tracer和交换机的端口配置与管理及Telnet远程登陆配置
实验一 实验名称 使用网络模拟器Packet Tracer 实验目的 1. 掌握安装和配置网络模拟器PacketTracer的方法: 2. 掌握使用PacketTracer模拟网络场景的基本方法,加深 ...
- Asterisk manager API(AMI)文档(中文版)
Asterisk控制接口(AMI)允许管理客户端程序连接到一个asterisk实例并且可以通过TCP/IP流发送命令或读取事件.这在试图跟踪asterisk的状态或其中的电话客户端状态时很有用,AMI ...
- 呼叫我,或异步REST
本文是使用Spring Boot + Java 8进行的异步REST应用程序工作的非常简单的示例.SpringBoot使Web应用程序的开发几乎非常容易,但是为了简化任务,我从Spring存储库中举了 ...
- CRM呼叫中心异步搜索实现的调试截图
要获取更多Jerry的原创文章,请关注公众号"汪子熙":
- SAP CRM呼叫中心异步搜索功能的实现
Created by Wang, Jerry, last modified on Dec 12, 2014 要获取更多Jerry的原创文章,请关注公众号"汪子熙":
- 《实施Cisco统一通信管理器(CIPT1)》一2.4 使用分布式呼叫处理的多站点WAN部署模型...
本节书摘来异步社区<实施Cisco统一通信管理器(CIPT1)>一书中的第2章,第2.4节,作者: [美]Dennis Hartmann 译者: 刘丹宁 , 陈国辉 , 卢铭 责编: 傅道 ...
- C#:异步编程和线程的使用(.NET 4.5 ),异步方法改为同步执行
摘自:http://www.codeproject.com/Articles/996857/Asynchronous-programming-and-Threading-in-Csharp-N(葡萄城 ...
- 如何从异步调用返回响应?
我有一个函数foo ,它发出Ajax请求. 如何返回foo的响应? 我尝试从success回调中返回值,以及将响应分配给函数内部的局部变量并返回该局部变量,但这些方法均未真正返回响应. functio ...
最新文章
- 数据结构与算法分析c++第四版_研分享 | 人工智能学院数据结构与算法分析考研备考整理...
- gitweb的安装(四)
- 求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)
- 收藏 | 2020年腾讯技术工程十大热门文章
- c语言长整数转化为16进制字符串,一个30位的字符串十进制长整数怎么转换为对应的十六进制和八进制...
- eclipse没有日志_强化公共DHT以抵抗eclipse攻击,ipfs官方还说了什么?
- Linux服务器的显卡驱动丢失又装上的过程
- Flutter状态管理学习手册(三)——Bloc
- springbootspringboot杏林中医诊所管理系统133742
- Solidity语言详解——view和pure函数的使用区别
- 那些普通人的价值观终究会害了你
- 期刊缩写合辑【JCR+ISO】
- 2017-5-11 公司客户考察篇
- 郭彦甫Matlab第四节笔记——初阶绘图
- Ansible 第二章
- “撸啊”不止能秒杀!| lua+redis实现高并发抢令牌
- 企业网络安全问题的痛点分析
- 伺服驱动器和电机控制
- 企业文化和品牌文化是两回事
- 三拼域名会成为未来投资新趋势吗?哪类三拼域名值得投资?