SpringBoot异步方法(官方案例)

news2025/1/15 17:46:07
  1. 在线文档
  2. 项目结构
    1.源码克隆:git clone https://github.com/spring-guides/gs-async-method.git
    2.包含两个项目initial和complete,initial可以根据文档练习完善,complete是完整项目
    3.功能描述:构建查找服务,异步查询 GitHub 用户信息并通过 GitHub 的 API 检索数据

  3. 源码分析

    1.POM依赖
    <dependencies>
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-web</artifactId>
    	</dependency>
    
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-test</artifactId>
    		<scope>test</scope>
    	</dependency>
    </dependencies>
    2.入口类
    // https://blog.csdn.net/tongxin_tongmeng/article/details/128401278
    @SpringBootApplication
    // https://blog.csdn.net/tongxin_tongmeng/article/details/128583490
    @EnableAsync
    public class AsyncMethodApplication {
    
    	public static void main(String[] args) {
    		// close the application context to shut down the custom ExecutorService
    		SpringApplication.run(AsyncMethodApplication.class, args).close();
    	}
    
    	/**
    	 * 这段代码定义了一个 Executor 对象,该对象是使用 ThreadPoolTaskExecutor 类创建的线程池。Executor 是一个接口,它定义了一种方法来异步地执行任务。
    	 *
    	 * ThreadPoolTaskExecutor 是一个实现了 Executor 接口的类,它使用线程池来执行任务。线程池是一种管理线程的机制,它提供了一种可伸缩的线程池,用于在应用程序中执行异步任务。
    	 *
    	 * 在这段代码中,我们设置了线程池的核心线程数(corePoolSize)和最大线程数(maxPoolSize)为 2,以及队列的容量(queueCapacity)为 500。我们还为线程池中的线程设置了名称前缀(threadNamePrefix)。最后,我们调用 initialize() 方法来初始化线程池。
    	 *
    	 * 这段代码还使用了 @Bean 注解,该注解表示此方法将会在应用程序上下文中生成一个 bean。这意味着,你可以在应用程序的其他地方使用这个 Executor 对象。
    	 *
    	 * 例如,你可以在另一个类中注入这个 Executor 对象并使用它来异步地执行任务:
    	 * @Autowired
    	 * private Executor taskExecutor;
    	 *
    	 * public void doSomething() {
    	 *   taskExecutor.execute(new Runnable() {
    	 *     @Override
    	 *     public void run() {
    	 *       // do something
    	 *     }
    	 *   });
    	 * }
    	 * @return
    	 */
    	@Bean
    	public Executor taskExecutor() {
    		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    		executor.setCorePoolSize(2);
    		executor.setMaxPoolSize(2);
    		executor.setQueueCapacity(500);
    		executor.setThreadNamePrefix("GithubLookup-");
    		executor.initialize();
    		return executor;
    	}
    	
    }
    3.接口类
    @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();
    	}
    
    	/**
    	 * 这段代码定义了一个名为 findUser() 的方法,它使用 RestTemplate 发送一个 GET 请求到 GitHub API,获取指定用户的信息并返回。方法的返回值是 CompletableFuture 类型,它可以用于执行异步操作。
    	 *
    	 * @Async 注解告诉 Spring 在单独的线程中执行 findUser() 方法。这意味着 findUser() 方法的调用将立即返回,而不等待方法实际完成。你可以在其他代码中继续执行其他任务,而无需等待 findUser() 方法的响应返回。
    	 *
    	 * findUser() 方法返回的 CompletableFuture 对象可以用于获取方法执行的结果。例如,你可以使用 thenApply() 方法在方法执行完成后对结果进行处理:
    	 * CompletableFuture<User> future = findUser("some-user");
    	 * future.thenApply(user -> {
    	 *     // Do something with the result
    	 *     return user;
    	 * });
    	 * @param user
    	 * @return
    	 * @throws InterruptedException
    	 */
    	@Async
    	public CompletableFuture<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 purposes
    		Thread.sleep(1000L);
    		return CompletableFuture.completedFuture(results);
    	}
    
    }
    4.测试类
    /**
     * 这段代码定义了一个名为 AppRunner 的组件,它实现了 CommandLineRunner 接口,因此在 Spring 应用程序启动时会执行 run() 方法。
     *
     * AppRunner 类持有一个名为 gitHubLookupService 的 GitHubLookupService 类型的引用,并在构造函数中将其注入。GitHubLookupService 类是一个用于查找 GitHub 用户信息的服务。
     *
     * 在 run() 方法中,代码首先记录了当前时间,然后使用 gitHubLookupService 发出三个异步请求来查找三个 GitHub 用户。请求返回的是 CompletableFuture 类型的对象,这些对象会被存储在 page1、page2 和 page3 中。
     *
     * 接下来,代码调用 allOf() 方法,该方法接受多个 CompletableFuture 对象并返回一个新的 CompletableFuture,该 CompletableFuture 将在所有传入的 CompletableFuture 对象都完成后完成。allOf() 方法的返回值被加入,这意味着程序将在所有请求完成后再继续执行。
     *
     * 最后,代码打印了每个请求的结果以及整个操作所用的时间。get() 方法用于获取 CompletableFuture 对象的结果。
     */
    @Component
    // https://blog.csdn.net/tongxin_tongmeng/article/details/128402169
    public class AppRunner implements CommandLineRunner {
    
    	private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
    
    	private final GitHubLookupService gitHubLookupService;
    
    	public AppRunner(GitHubLookupService gitHubLookupService) {
    		this.gitHubLookupService = gitHubLookupService;
    	}
    
    	@Override
    	public void run(String... args) throws Exception {
    		// Start the clock
    		long start = System.currentTimeMillis();
    
    		// Kick of multiple, asynchronous lookups
    		CompletableFuture<User> page1 = gitHubLookupService.findUser("PivotalSoftware");
    		CompletableFuture<User> page2 = gitHubLookupService.findUser("CloudFoundry");
    		CompletableFuture<User> page3 = gitHubLookupService.findUser("Spring-Projects");
    
    		// Wait until they are all done
    		CompletableFuture.allOf(page1,page2,page3).join();
    
    		// Print results, including elapsed time
    		logger.info("Elapsed time: " + (System.currentTimeMillis() - start));
    		logger.info("--> " + page1.get());
    		logger.info("--> " + page2.get());
    		logger.info("--> " + page3.get());
    
    	}
    
    }
  4. 项目演示
    前两个调用发生在不同的线程 ( GithubLookup-2, GithubLookup-1) 中,第三个调用被暂停,直到两个线程之一可用为止。
    要比较在没有异步功能的情况下这需要多长时间,请尝试注释掉@Async注释并再次运行该服务。总耗用时间应该会显着增加,
    因为每个查询至少需要一秒钟。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/145412.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux搭建Docker版FTP,命令与Dockerfile两种方式以及容器编码解决

Linux搭建Docker版FTP&#xff0c;命令与Dockerfile两种方式以及容器编码解决一、Linux搭建Docker版FTP二、修改 Docker 容器内部 locale 系统编码最终待实现效果&#xff0c;这个方式容器内部编码并未永久改变三、编写Dockerfile方式加载带UTF-8编码环境的镜像3.1Dockerfile构…

【LINUX权限】

目录&#xff1a;前言一、shell二、权限&#xff08;一&#xff09;文件权限&#xff08;二&#xff09;权限相关指令chmod&#xff08;修改权限&#xff09;su 、sudo&#xff08;提权&#xff09;root提权chown 、chgrpumask&#xff08;掩码&#xff09;file&#xff08;三&…

性能测试工具 Lmbench 的使用方法以及解析运行结果

1. Lmbench 简介 Lmbench 是一款简易可以移植的内存测试工具&#xff0c;其主要功能有&#xff0c;带宽测评&#xff08;读取缓存文件、拷贝内存、读/写内存、管道、TCP&#xff09;&#xff0c;延时测评&#xff08;上下文切换、网络、文件系统的建立和删除、进程创建、信号处…

MYSQL中的14个实用的功能

1.group_concat 在我们平常的工作中,使用group by进行分组的场景,是非常多的。 比如想统计出用户表中,名称不同的用户的具体名称有哪些? 具体sql如下: select name from `user` group by name; 但如果想把name相同的code拼接在一起,放到另外一列中该怎么办呢? 答:…

Genesis一款基于Domino的app store应用超市

大家好&#xff0c;才是真的好。 众所周知&#xff0c;App Store是苹果iOS系统生态成功的关键因素。Domino作为一款企业应用平台&#xff0c;很多年前&#xff0c;就有人提出要创建Domino平台上的App Store。 其实比IOS早很多年前就有类似的应用管理&#xff0c;早在2000年的…

代码随想录之回溯第一课

要领&#xff1a;类型题目&#xff0c;用具体的一个例子来记忆&#xff0c;就够了&#xff0c;印象更加深刻。 一个题目&#xff0c;感觉理解不深刻&#xff0c;不透彻&#xff0c;不清晰&#xff0c;不熟练&#xff0c;就是不达标。 怎么做&#xff1f; 每天回顾复习看一次&am…

DD-1/50 12.5-50mA【接地继电器】

系列型号&#xff1a; DD-1/40接地继电器 DD-1/50接地继电器 DD-1/60接地继电器 一、 用途及工作原理 DD-1型接地继电器为瞬时动作的过电流继电器&#xff0c;用作小电流接地电力系统高电压三相交流发电机和电动机的接地零序过电流保护。继电器线圈接零序电流互感器(电缆式、…

电脑重装系统后分辨率不对应该怎么调

越来越多的小伙伴使用小白一键重装系统给自己的电脑安装上了win10系统&#xff0c;但是有部分小伙伴发现安装完win10系统之后&#xff0c;屏幕分辨率也无法进行调整&#xff0c;呈灰色状态。接下来小编就给大家详细的介绍一下小白一键重装系统分辨率不对怎么调的教程。 工具/原…

【Django】(一)基础知识

文章目录一.安装二.创建项目三.项目介绍四.APP的创建五.小案例六 模板和静态文件模板静态文件7.模板语法7.1 变量7.2列表7.3 字典7.4 过滤器7.5 if/else7.6 for标签7.7 ifequal和ifnotequal7.8注释7.9csrf_token8.模板继承8.1父模板8.2 子模板9.请求和响应10.数据库10.1安装第三…

【服务器搭建个人网站】附:接入的服务商 以及 安全评估报告该如何填写?

前言 哈喽&#xff0c;大家好&#xff0c;我是木易巷&#xff01; 关于公安备案的一些详细的细节没有分享出来&#xff0c;在公安备案期间要填写很多东西&#xff0c;其中比较难填写的就是接入的服务商和安全评估报告的填写。 这一篇给大家总结&#xff1a;公安备案接入服务商和…

⭐️【linux】关于linux-gcc,你必须要知道的知识

&#x1f332;&#x1f332;目录&#x1f332;&#x1f332; 1️⃣什么是gcc 2️⃣gcc如何生成可执行文件 3️⃣简单使用gcc 4️⃣linux的库 1️⃣什么是gcc ❄️GCC&#xff08;GNU Compiler Collection&#xff0c;GNU编译器套件&#xff09;&#xff0c;是由 GNU 开发的…

Java 中 Map 集合的基本使用

一、HashMap 1.1 HashMap 基本使用 import java.util.*;/*** author: yunhu* date: 2022/7/14*/ public class Test {public static void main(String[] args) {Map<String, Integer> map new HashMap<>();map.put("Alice", 12);map.put("Bob&qu…

62.Python 类的3要素语法

62.类的3要素语法 文章目录62.类的3要素语法1. 定义类的语法2. pass语句的作用3.我们学的5个缩进语法4.类的属性5.类的方法6. 创建对象7.类在爬虫中的应用8. 总结1. 定义类的语法 定义类的语法如下&#xff1a; class 类名: 代码块 从语法上来看&#xff1a;类的…

Edify Script (Android Shell)定制Twrp刷机包

本文将通过三方面向大家介绍Edify Script,相信你看完了这篇文章会对安卓系统可刷写插件有一个比较完整的认识,并且能过通过阅读此文章实现使用twrp刷入自己写的插件zipi包。网上能搜到的大部分是旧的,新版本去掉了很多的edify函数,照着他们那个写多半会报错。 本文分为如下…

LeetCode学习-第三十八天

第三十八天 我使用的C&#xff0c;错误的地方请见谅&#xff0c;文章初衷仅用来督促本人学习&#xff0c;如果恰巧能够给你带来帮助&#xff0c;我会十分开心。 文章目录第三十八天一、537. 复数乘法二、29. 两数相除一、537. 复数乘法 复数 可以用字符串表示&#xff0c;遵循…

CentOS7如何修改IP地址及UUID

CentOS7系统下&#xff0c;如果要把IP地址修改为192.168.1.80&#xff0c;子网掩码是255.255.255.0&#xff0c;网关是192.168.1.1&#xff0c;DNS是192.168.1.1&#xff0c;那么我们使用客户端连接CentOS或者打开系统终端&#xff0c;切换到root用户&#xff0c;命令&#xff…

开料的目的和子流程,一文读懂

经过多个月的分享&#xff0c;关于PCB行业&#xff0c;想必朋友们已经有了一些个人的理解&#xff0c;甚至对PCB行业&#xff0c;还产生了浓厚的兴趣。 但是&#xff0c;PCB生产工艺是非常复杂的&#xff0c;想要深入地学习并且学好PCB生产工艺&#xff0c;假如不在PCB的生产一…

如何从PyTorch中获取过程特征图

一、获取Tensor 神经网络在运算过程中实际上是以Tensor为格式进行计算的&#xff0c;我们只需稍稍改动一下forward函数即可从运算过程中抓到Tensor 代码如下&#xff1a; base_feature self.extractor.forward(x) #正常的前向传递 featurebase_feature.detach() …

JavaScript 数据类型

文章目录JavaScript 数据类型JavaScript 拥有动态类型JavaScript 字符串JavaScript 数字JavaScript 布尔JavaScript 数组JavaScript 对象Undefined 和 Null声明变量类型JavaScript 数据类型 字符串&#xff08;String&#xff09;、数字(Number)、布尔(Boolean)、数组(Array)、…

基于java eclipse+jsp+mysql+servlet+Spring的学生信息管理系统基础版

基于java eclipsejspmysqlservletSpring的学生信息管理系统基础版 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…