Spring框架提供的异步执行能力
Spring Framework分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象。本节我们着重讲解@Async如何实现异步处理。
二、 @Scheduled@Scheduled注释可以与触发器元数据一起添加到方法中。例如,以固定延迟每5秒调用以下方法,这意味着将从每个前一次调用的完成时间开始测量该周期,例如:
@Scheduled(fixedDelay=5000)public void doSomething() { // something that should execute periodically}
如果需要固定费率执行,只需更改注释中指定的属性名称即可。在每次调用的连续开始时间之间测量的每5秒执行以下操作:
@Scheduled(fixedRate=5000)public void doSomething() { // something that should execute periodically}
如果简单的周期性调度不够表达,则可以提供cron表达式。例如,以下内容仅在工作日执行:
@Scheduled(cron="*/5 * * * * MON-FRI")public void doSomething() { // something that should execute on weekdays only}
请注意,要调度的方法必须具有void返回,并且不得指望任何参数。如果该方法需要与Application Context中的其他对象进行交互,则通常会通过依赖注入提供这些对象。
需要注意的是该注解默认是不会解析的,需要加上@EnableScheduling 来启动。
三、 @Async
可以在方法上添加@Async注释,以便异步调用该方法。换句话说,调用者将在调用时立即返回,并且该方法的实际执行将发生在Spring TaskExecutor中。
@Async public void dosomthingAsync() {
System.out.println("--dosomthingAsync begin---"); // 模拟异步处理 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("--dosomthingAsync end---"); }
如上代码在方法dosomthingAsync上添加了@Async的注解,所以当我们调用dosomthingAsync方法时候,该方法会马上返回。
与使用@Scheduled注解的方法不同,@Async可以有返回值,因为它们将在运行时由调用者以“正常”方式调用,而不是由容器管理的调度任务调用。例如,以下是@Async注解的合法应用程序:
@Componentpublic class AsyncTask {... @Async public CompletableFuture String dosomthingAsyncFuture() {
System.out.println("--dosomthingAsync begin---"); CompletableFuture String future = new CompletableFuture String
// 模拟异步处理 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } future.complete("ok"); System.out.println("--dosomthingAsync end---");
return future; }}
如上代码调用该方法后,该方法会马上返回一个CompletableFuture对象,如果你一直持有这个CompletableFuture对象,那么等dosomthingAsyncFuture内业务处理异步处理完毕后,就可以从dosomthingAsyncFuture的get()方法获取到执行结果。那么Spring框架是如何做到我们dosomthingAsyncFuture时候会马上返回一个CompletableFuture那?其实其对该类进行了代理,经过代理后的上面的方法类似于:
public class AsynTaskProxy {
public AsyncTask getAsyncTask() { return asyncTask; }
public void setAsyncTask(AsyncTask asyncTask) { this.asyncTask = asyncTask; }
private AsyncTask asyncTask;
private TaskExecutor executor = new SimpleAsyncTaskExecutor();
public CompletableFuture String dosomthingAsyncFuture() {
return CompletableFuture.supplyAsync(new Supplier String () {
@Override public String get() { try { return asyncTask.dosomthingAsyncFuture().get(); } catch (Throwable e) { throw new CompletionException(e); } } }); }}
Spring会对AsyncTask类使用类似的AsynTaskProxy进行代理,并且会把AsynTask的实例注入到AsynTaskProxy内部,当我们调用AsynTask的dosomthingAsyncFuture方法时候,实际调用的是AsynTaskProxy的dosomthingAsyncFuture方法,后者则使用 CompletableFuture.supplyAsync开启了一个异步任务(其马上返回一个 CompletableFuture对象),并且使用默认的SimpleAsyncTaskExecutor线程池做为异步处理线程,然后异步任务内在具体调用了 AsyncTask实例的dosomthingAsyncFuture方法,并且在返回的future上获取执行结果。
默认情况下,Spring将搜索关联的线程池定义:Spring上下文容器中的唯一的org.springframework.core.task.TaskExecutor类型的bean,如果不存在,则查找名为“taskExecutor”的java.util.concurrent.Executo的 bean。如果两者都不存在,则将使用org.springframework.core.task.SimpleAsyncTaskExecutor的一个实例来处理异步方法调用。
SimpleAsyncTaskExecutor中对每个异步任务对应开启一个线程来进行处理,会造成线程频繁创建与销毁,没有进行线程复用,所以我们可以创建自己的线程池,比如下面:
@Bean public TaskExecutor bizExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(8); executor.setCorePoolSize(8); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setQueueCapacity(5);
return executor; }
则当bizExecutor通过@Bean注入到Spring上下文中后,异步处理就使用其中线程池进行处理。
需要注意的是该注解默认是不会被解析的,需要加上@EnableAsync来启动。
本文翻译自https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async
并融入作者自己理解。
欢迎关注微信公众号:技术原始积累
原创文章,转载请注明: 转载自并发编程网 ifeve.com本文链接地址: Spring框架提供的异步执行能力
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/60291.html
相关文章
- spring boot自动配置原理面试题_Spring boot面试
- Spring学习笔记(三十三)——SpringBoot集成Swagger
- Spring MVC框架学习(二)---- 使用原生的配置 熟悉 SpringMVC 的执行流程
- 基于Spring Boot、Vue的考试报名系统设计与实现-前后端分离-课程设计-毕业设计一键部署版
- Spring基础(二):IOC概念引入
- Spring Boot执行延时任务-DelayQueue的使用
- Spring Boot 中使用@Async实现异步调用,加速任务执行!
- Spring Cloud Gateway过滤器的执行顺序
- Spring Cloud Task查看任务执行日志
- Spring MVC @Controller和@RequestMapping注解
- 使用Spring定时任务并且通过AOP监控任务执行情况详解编程语言
- Spring Boot搭建Web应用详解编程语言
- drools6的kie-spring集成使用详解编程语言
- Spring-data-jpa 学习笔记(二)详解编程语言
- Spring开启方法异步执行详解编程语言
- Spring boot 自定义拦截器详解编程语言
- spring web.xml配置服务启动后执行文件详解编程语言
- Spring batchUpdate方法:执行批量更新语句
- spring使用Spring整合Redis和Jedis构建高性能应用(redisjedis与)
- Spring框架下整合Redis的实现(spring整合redis)
- spring架构利器:JFinal MySQL Spring(jfinalmysql)
- Spring Boot 2.x :通过 spring-boot-starter-hbase 集成 HBase