使用spring boot的程序主线程中异步访问外部接口

2023-10-28 16:30

本文主要是介绍使用spring boot的程序主线程中异步访问外部接口,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如题。之所以要采用异步方式,是因为外部接口不可控,无法预测。如果对方不在线,因而无法访问,只有靠超时抛出异常,容易造成堵塞。

比如下面的代码,有2个定时器,其中刷新设备数据每2秒1次,检查外部接口每10秒1次。可是由于外部接口访问超时,导致刷新设备数据受到影响,不能按时触发。

1、原来容易堵塞的代码

@Component
public class RefreshData {@AutowiredEquipDataService equipDataService;@Scheduled(fixedRate = 2000)  // 刷新设备数据,每 2 秒执行一次public void printMessage() {System.out.println("每 2 秒读取最新数据.");equipDataService.freshData();}@Scheduled(fixedRate = 10000)  // 检查外部接口等连接情况,每 10 秒执行一次public void printMessage2() {System.out.println("每 10 秒检查各部件连接情况.");equipDataService.freshCheckLink();}
}
public interface EquipDataService {void freshData();void freshCheckLink();
}
@Service
public class EquipDataServiceImpl implements EquipDataService {。。。@Overridepublic void freshCheckLink() {。。。getOuterApi();}private void getOuterApi() {String url = String.format("%s/test", outerApiUrl);String content = HttpUtils.callGet(url);//采用get方式访问url。自定义函数。return content != null && content.compareTo("ok") == 0;}
}

2、采用异步模式的代码

很容易想到采用多线程方案。但如果不想大动干戈,修改太多代码,也可以采用异步模式访问外部接口。

import java.util.concurrent.CompletableFuture;@Service
public class EquipDataServiceImpl implements EquipDataService {。。。@Overridepublic void freshCheckLink() {getOuterApi();}private void getOuterApi() {CompletableFuture.supplyAsync(() -> {try {String url = String.format("%s/test", outerApiUrl);String content = HttpUtils.callGet(url);//采用get方式访问url。自定义函数。return content != null && content.compareTo("ok") == 0;} catch (Fault fault) {System.out.println(fault.getCause());return null;} catch (Exception e) {System.out.println(e.getCause());return null;}}).thenAccept(ok -> {if (ok != null) {。。。} else {System.out.println("Error occurred while retrieving outerApiUrl"));}}).exceptionally(ex -> {System.out.println(String.format("visit outerApiUrl Error occurred: %s", ex.getCause()));});}
}

3、小结

CompletableFuture.supplyAsync 是 Java 并发编程中 CompletableFuture 类的一个静态工厂方法,用于创建一个异步执行的 CompletableFuture 对象,它会在后台线程中执行指定的操作,并返回一个结果。这个方法的签名如下:

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

其中:

<U> 是结果的类型。
Supplier<U> 是一个函数式接口,它没有参数并返回一个值。在 supplyAsync 中,这个接口表示一个计算任务,它会异步执行,计算并返回一个结果。
使用 CompletableFuture.supplyAsync 可以在并发环境中执行某些操作,然后使用 CompletableFuture 对象来处理结果或执行后续操作。这是 Java 并发编程中一种方便的异步编程方式。

下面是一个简单的示例,演示了如何使用 CompletableFuture.supplyAsync 来异步执行一个任务:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureExample {public static void main(String[] args) {CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 这里是异步计算的任务return 42;});try {// 获取异步任务的结果int result = future.get();System.out.println("异步任务的结果: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

在上面的示例中,supplyAsync 异步执行了一个计算任务,返回结果 42。通过 future.get() 获取异步任务的结果。需要注意,get 方法会阻塞直到任务完成并返回结果或抛出异常。在实际应用中,通常会结合其他 CompletableFuture 方法来构建更复杂的异步处理流程。

CompletableFuture.supplyAsync 具有许多好处,使其在 Java 并发编程中非常有用:

  1. 异步执行supplyAsync 创建的 CompletableFuture 对象会在后台线程中异步执行指定的任务。这允许您在不阻塞主线程的情况下执行耗时的操作,从而提高程序的并发性和响应性。

  2. 可组合性CompletableFuture 支持各种方法,允许您对异步操作进行组合、串行化、并行化等操作。您可以轻松地构建复杂的异步处理流程。

  3. 错误处理:您可以通过 exceptionallyhandle 等方法来处理异步操作中可能发生的异常,使代码更健壮。

  4. 超时处理CompletableFuture 允许您设置超时操作,以防异步任务耗时过长。

  5. 并行处理:您可以使用 thenCombine, thenCompose 等方法将多个 CompletableFuture 组合在一起,以实现并行处理多个异步操作。

  6. 非阻塞获取结果:通过 join()getNow() 方法,可以非阻塞地获取异步操作的结果。这使得在需要结果时可以等待,而不必一直阻塞主线程。

  7. 适用于网络请求和IO操作CompletableFuture 是处理网络请求、数据库查询和其他需要等待外部资源的任务的理想选择,因为它可以在等待资源返回时不阻塞主线程。

  8. 可读性和维护性CompletableFuture 的使用可以使代码更具可读性和维护性,特别是在处理复杂的异步操作流程时。

总之,CompletableFuture.supplyAsync 提供了一种强大的工具,使您能够以异步方式执行操作,充分利用多核处理器和提高程序性能,同时保持代码的清晰性和可维护性。这在需要处理异步任务的现代应用程序中非常有用。

这篇关于使用spring boot的程序主线程中异步访问外部接口的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/294467

相关文章

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J