- 浏览: 147543 次
- 性别:
- 来自: 北京
文章分类
最新评论
Spring Boot中使用@Async实现异步调用
什么是“异步调用”?
“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。
同步调用
下面通过一个简单示例来直观的理解什么是同步调用:
- 定义Task类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内)
|
|
-
在单元测试用例中,注入Task对象,并在测试用例中执行
doTaskOne
、doTaskTwo
、doTaskThree
三个函数。
|
|
- 执行单元测试,可以看到类似如下输出:
|
|
任务一、任务二、任务三顺序的执行完了,换言之doTaskOne
、doTaskTwo
、doTaskThree
三个函数顺序的执行完成。
异步调用
上述的同步调用虽然顺利的执行完了三个任务,但是可以看到执行时间比较长,若这三个任务本身之间不存在依赖关系,可以并发执行的话,同步调用在执行效率方面就比较差,可以考虑通过异步调用的方式来并发执行。
在Spring Boot中,我们只需要通过使用@Async
注解就能简单的将原来的同步函数变为异步函数,Task类改在为如下模式:
|
|
为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:
|
|
此时可以反复执行单元测试,您可能会遇到各种不同的结果,比如:
- 没有任何任务相关的输出
- 有部分任务相关的输出
- 乱序的任务相关的输出
原因是目前doTaskOne
、doTaskTwo
、doTaskThree
三个函数的时候已经是异步执行了。主程序在异步调用之后,主程序并不会理会这三个函数是否执行完成了,由于没有其他需要执行的内容,所以程序就自动结束了,导致了不完整或是没有输出任务相关内容的情况。
注: @Async所修饰的函数不要定义为static类型,这样异步调用不会生效
异步回调
为了让doTaskOne
、doTaskTwo
、doTaskThree
能正常结束,假设我们需要统计一下三个任务并发执行共耗时多少,这就需要等到上述三个函数都完成调动之后记录时间,并计算结果。
那么我们如何判断上述三个异步调用是否已经执行完成呢?我们需要使用Future<T>
来返回异步调用的结果,就像如下方式改造doTaskOne
函数:
|
|
按照如上方式改造一下其他两个异步函数之后,下面我们改造一下测试用例,让测试在等待完成三个异步调用之后来做一些其他事情。
|
|
看看我们做了哪些改变:
- 在测试用例一开始记录开始时间
-
在调用三个异步函数的时候,返回
Future<String>
类型的结果对象 -
在调用完三个异步函数之后,开启一个循环,根据返回的
Future<String>
对象来判断三个异步函数是否都结束了。若都结束,就结束循环;若没有都结束,就等1秒后再判断。 - 跳出循环之后,根据结束时间 - 开始时间,计算出三个任务并发执行的总耗时。
执行一下上述的单元测试,可以看到如下结果:
|
|
可以看到,通过异步调用,让任务一、二、三并发执行,有效的减少了程序的总运行时间。
Spring Boot中使用@Scheduled创建定时任务
我们在编写Spring Boot应用中经常会遇到这样的场景,比如:我需要定时地发送一些短信、邮件之类的操作,也可能会定时地检查和监控一些标志、参数等。
创建定时任务
在Spring Boot中编写定时任务是非常简单的事,下面通过实例介绍如何在Spring Boot中创建定时任务,实现每过5秒输出一下当前时间。
-
在Spring Boot的主类中加入
@EnableScheduling
注解,启用定时任务的配置
|
|
- 创建定时任务实现类
|
|
- 运行程序,控制台中可以看到类似如下输出,定时任务开始正常运作了。
2016-05-15 10:40:04.073 INFO 1688 --- [ main] com.didispace.Application : Started Application in 1.433 seconds (JVM running for 1.967)
现在时间:10:40:09
现在时间:10:40:14
现在时间:10:40:19
现在时间:10:40:24
现在时间:10:40:29522
现在时间:10:40:34
关于上述的简单入门示例也可以参见官方的Scheduling Tasks
@Scheduled详解
在上面的入门例子中,使用了@Scheduled(fixedRate
= 5000)
注解来定义每过5秒执行的任务,对于@Scheduled
的使用可以总结如下几种方式:
-
@Scheduled(fixedRate = 5000)
:上一次开始执行时间点之后5秒再执行 -
@Scheduled(fixedDelay = 5000)
:上一次执行完毕时间点之后5秒再执行 -
@Scheduled(initialDelay=1000, fixedRate=5000)
:第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次 -
@Scheduled(cron="*/5 * * * * *")
:通过cron表达式定义规则
Spring Boot属性配置文件详解
相信很多人选择Spring Boot主要是考虑到它既能兼顾Spring的强大功能,还能实现快速开发的便捷。我们在Spring Boot使用过程中,最直观的感受就是没有了原来自己整合Spring应用时繁多的XML配置内容,替代它的是在pom.xml
中引入模块化的Starter
POMs
,其中各个模块都有自己的默认配置,所以如果不是特殊应用场景,就只需要在application.properties
中完成一些属性配置就能开启各模块的应用。
在之前的各篇文章中都有提及关于application.properties
的使用,主要用来配置数据库连接、日志相关配置等。除了这些配置内容之外,本文将具体介绍一些在application.properties
配置中的其他特性和使用方法。
自定义属性与加载
我们在使用Spring Boot的时候,通常也需要定义一些自己使用的属性,我们可以如下方式直接定义:
|
|
然后通过@Value("${属性名}")
注解来加载对应的配置属性,具体如下:
|
|
按照惯例,通过单元测试来验证BlogProperties中的属性是否已经根据配置文件加载了。
|
|
参数间的引用
在application.properties
中的各个参数之间也可以直接引用来使用,就像下面的设置:
|
|
com.didispace.blog.desc
参数引用了上文中定义的name
和title
属性,最后该属性的值就是程序猿DD正在努力写《Spring
Boot教程》
。
使用随机数
在一些情况下,有些参数我们需要希望它不是一个固定的值,比如密钥、服务端口等。Spring Boot的属性配置文件中可以通过${random}
来产生int值、long值或者string字符串,来支持属性的随机值。
|
|
通过命令行设置属性值
相信使用过一段时间Spring Boot的用户,一定知道这条命令:java
-jar xxx.jar --server.port=8888
,通过使用–server.port属性来设置xxx.jar应用的端口为8888。
在命令行运行时,连续的两个减号--
就是对application.properties
中的属性值进行赋值的标识。所以,java
-jar xxx.jar --server.port=8888
命令,等价于我们在application.properties
中添加属性server.port=8888
,该设置在样例工程中可见,读者可通过删除该值或使用命令行来设置该值来验证。
通过命令行来修改属性值固然提供了不错的便利性,但是通过命令行就能更改应用运行的参数,那岂不是很不安全?是的,所以Spring Boot也贴心的提供了屏蔽命令行访问属性的设置,只需要这句设置就能屏蔽:SpringApplication.setAddCommandLineProperties(false)
。
多环境配置
我们在开发Spring Boot应用时,通常同一套程序会被应用和安装到几个不同的环境,比如:开发、测试、生产等。其中每个环境的数据库地址、服务器端口等等配置都会不同,如果在为不同环境打包时都要频繁修改配置文件的话,那必将是个非常繁琐且容易发生错误的事。
对于多环境的配置,各种项目构建工具或是框架的基本思路是一致的,通过配置多份不同环境的配置文件,再通过打包命令指定需要打包的内容之后进行区分打包,Spring Boot也不例外,或者说更加简单。
在Spring Boot中多环境配置文件名需要满足application-{profile}.properties
的格式,其中{profile}
对应你的环境标识,比如:
-
application-dev.properties
:开发环境 -
application-test.properties
:测试环境 -
application-prod.properties
:生产环境
至于哪个具体的配置文件会被加载,需要在application.properties
文件中通过spring.profiles.active
属性来设置,其值对应{profile}
值。
如:spring.profiles.active=test
就会加载application-test.properties
配置文件内容
下面,以不同环境配置不同的服务端口为例,进行样例实验。
-
针对各环境新建不同的配置文件
application-dev.properties
、application-test.properties
、application-prod.properties
-
在这三个文件均都设置不同的
server.port
属性,如:dev环境设置为1111,test环境设置为2222,prod环境设置为3333 -
application.properties中设置
spring.profiles.active=dev
,就是说默认以dev环境设置 -
测试不同配置的加载
-
执行
java -jar xxx.jar
,可以观察到服务端口被设置为1111
,也就是默认的开发环境(dev) -
执行
java -jar xxx.jar --spring.profiles.active=test
,可以观察到服务端口被设置为2222
,也就是测试环境的配置(test) -
执行
java -jar xxx.jar --spring.profiles.active=prod
,可以观察到服务端口被设置为3333
,也就是生产环境的配置(prod)
-
执行
按照上面的实验,可以如下总结多环境的配置思路:
-
application.properties
中配置通用内容,并设置spring.profiles.active=dev
,以开发环境为默认配置 -
application-{profile}.properties
中配置各个环境不同的内容 - 通过命令行方式去激活不同环境的配置
Spring Boot中Web应用的统一异常处理
我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况。Spring Boot提供了一个默认的映射:/error
,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。
选择一个之前实现过的Web应用(Chapter3-1-2)为基础,启动该应用,访问一个不存在的URL,或是修改处理内容,直接抛出异常,如:
|
|
此时,可以看到类似下面的报错页面,该页面就是Spring Boot提供的默认error映射页面。
统一异常处理
虽然,Spring Boot中实现了默认的error映射,但是在实际应用中,上面你的错误页面对用户来说并不够友好,我们通常需要去实现我们自己的异常提示。
下面我们以之前的Web应用例子为基础(Chapter3-1-2),进行统一异常处理的改造。
-
创建全局异常处理类:通过使用
@ControllerAdvice
定义统一的异常处理类,而不是在每个Controller中逐个定义。@ExceptionHandler
用来定义函数针对的异常类型,最后将Exception对象和请求URL映射到error.html
中
|
|
-
实现
error.html
页面展示:在templates
目录下创建error.html
,将请求的URL和Exception对象的message输出。
|
|
启动该应用,访问:http://localhost:8080/hello
,可以看到如下错误提示页面。
通过实现上述内容之后,我们只需要在Controller
中抛出Exception
,当然我们可能会有多种不同的Exception
。然后在@ControllerAdvice
类中,根据抛出的具体Exception
类型匹配@ExceptionHandler
中配置的异常类型来匹配错误映射和处理。
返回JSON格式
在上述例子中,通过@ControllerAdvice
统一定义不同Exception映射到不同错误处理页面。而当我们要实现RESTful
API时,返回的错误是JSON格式的数据,而不是HTML页面,这时候我们也能轻松支持。
本质上,只需在@ExceptionHandler
之后加入@ResponseBody
,就能让处理函数return的内容转换为JSON格式。
下面以一个具体示例来实现返回JSON格式的异常处理。
- 创建统一的JSON返回对象,code:消息类型,message:消息内容,url:请求的url,data:请求返回的数据
|
|
- 创建一个自定义异常,用来实验捕获该异常,并返回json
|
|
-
Controller
中增加json映射,抛出MyException
异常
|
|
-
为
MyException
异常创建对应的处理
|
|
|
|
至此,已完成在Spring Boot中创建统一的异常处理,实际实现还是依靠Spring MVC的注解,更多更深入的使用可参考Spring MVC的文档。
相关推荐
在Spring Boot中,可以使用@Async注解来实现异步调用。 使用@Async实现异步调用 在Spring Boot中,使用@Async注解可以将方法异步执行。@Async注解可以应用于方法上,使得该方法可以异步执行。例如: ```java @...
在Spring Boot中,异步调用是通过Spring的`@Async`注解来实现的,它允许我们在不阻塞主线程的情况下执行耗时的操作。这极大地提高了应用的响应速度,尤其是在处理大量并发请求时。接下来,我们将深入探讨如何在...
下面将详细解释如何在Spring Boot中使用`@Async`实现异步调用,以及其背后的原理。 首先,要启用`@Async`注解的功能,需要在Spring Boot的主配置类上添加`@EnableAsync`注解。这会告诉Spring框架,你需要异步任务的...
在Spring Boot框架中,@Async注解是实现异步任务处理的关键工具,它允许开发者将耗时的操作从主线程中分离出来,以提高应用程序的响应速度。本文将深入探讨@Async的工作原理、配置方法以及使用场景,帮助你更好地...
Spring Boot 异步调用 @Async 过程详解是 Spring Boot 框架中的一种异步调用机制,通过使用 @Async 注解可以将方法异步执行,提高系统的并发性和响应速度。本文将详细介绍 Spring Boot 异步调用 @Async 过程详解的...
在Spring Boot应用中,我们可以利用`@Async`注解实现异步调用,这有助于提高应用程序的并发性能,尤其在处理耗时操作时。本文将详细介绍如何使用`@Async`结合`Future`来处理异步任务,并探讨如何定义超时。 `@Async...
在Spring Boot中,启用...总结起来,Spring Boot中的异步调用通过`@Async`注解实现,可以显著提高应用的响应速度,特别是在处理耗时任务时。同时,合理的线程池配置和异常处理策略是确保异步功能高效、稳定运行的关键。
Spring Boot 框架提供了 @Async 注解来支持异步任务执行,该注解可以将方法调用转换为异步调用,从而提高应用程序的并发能力和响应速度。下面是关于 Spring Boot @Async 异步任务执行方法的详细知识点: 1. ...
* 最简单的异步调用,返回值为 void,基于 @Async 无返回值调用,直接在使用类,使用方法上,加上注解。 * 带参数的异步调用,异步方法可以传入参数。 * 异常调用返回 Future,不会被 AsyncUncaughtExceptionHandler...
在高并发的Web应用中,提高接口的并发处理能力是至关重要的,而SpringBoot框架提供了一种简单有效的方法——使用`@Async`注解来实现异步调用,从而优化性能。本文将深入探讨什么是异步调用,以及如何在SpringBoot中...
在Spring Boot应用中,`@Async`注解用于实现异步方法执行,这极大地提高了应用程序的并发性能。本文将深入探讨`@Async`的工作原理、使用场景以及如何配置和测试。 1. **异步注解的启用** 使用`@EnableAsync`注解在...
在Spring Boot应用中,使用`@Async`注解可以方便地实现异步任务,而`ThreadPoolTaskScheduler`作为Spring提供的一个任务调度器,允许我们创建一个定制化的线程池来处理这些异步任务。本文将深入探讨如何优雅地关闭`...
Spring Boot @Async 异步方法是 Spring Boot 框架中的一种异步编程方式,允许开发者在不阻塞主线程的情况下执行高耗时方法。下面将详细介绍 Spring Boot @Async 异步方法的使用和原理。 什么是异步调用 异步调用是...
Spring Boot 多线程 Demo Spring Boot 中使用多线程的方式有很多种,最简单的方式就是使用 @...使用 @Async 注解可以非常方便地实现多线程编程,在 Spring Boot 中使用 @Async 注解可以很容易地实现异步方法的调用。
在传统Spring应用中使用spring-boot-actuator模块提供监控端点 Spring Boot应用的后台运行配置 Spring Boot自定义Banner Dubbo进行服务治理 chapter9-2-1:Spring Boot中使用Dubbo进行服务治理 chapter9-2-2:Spring...
Spring Boot中实现异步调用的核心在于`@Async`注解。这个注解可以应用在方法上,表明该方法应被异步执行。为了启用Spring Boot的异步支持,我们需要在主配置类(通常为包含`@SpringBootApplication`注解的类)上添加...
1. **启用异步支持**:要在Spring Boot项目中使用异步方法,首先需要启用异步支持。这可以通过在配置类上添加`@EnableAsync`注解完成。例如: ```java import org.springframework.scheduling.annotation....
7. **@Async 实现异步调用**:使用`@Async`注解,开发者可以创建异步方法,提高应用程序的并发性能。这对于长时间运行的任务尤其有用,因为它不会阻塞主线程。 8. **日志管理**:Spring Boot 默认集成了Logback或...
首先,在 Spring Boot 主类上使用 @EnableAsync 注解来启动异步调用: ```java package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure....
在给定的"spring-boot-async-test.zip"压缩包中,包含了一个示例,演示了两种不同类型的异步请求:一种是没有返回值的异步请求,另一种是有返回值的异步请求。 首先,让我们详细了解一下Spring Boot中的异步处理...