springboot+async异步接口实现和调用

什么是异步调用?

异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行。

如何实现异步调用?

多线程,这是很多人第一眼想到的关键词,没错,多线程就是一种实现异步调用的方式。

在非spring目项目中我们要实现异步调用的就是使用多线程方式,可以自己实现Runable接口或者集成Thread类,或者使用jdk1.5以上提供了的Executors线程池。

StrngBoot中则提供了很方便的方式执行异步调用。

异步接口的使用场景

耗时比较长,任务比较多的接口。比方说,文件下载,大文件下载比较耗时,这个时候就可以使用异步接口。

示例

代码入下

maven依赖:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies> 

启动类:添加@EnableAsync注解

@SpringBootApplication
@EnableAsync
public class Application{  

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
} 

Controller

只需在需要异步执行方法上添加@Async注解

@RestController
@RequestMapping("")
public class AsyncTaskController {  

    @RequestMapping("")
    public String doTask() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        this.task1();
        this.task2();
        this.task3();
        long currentTimeMillis1 = System.currentTimeMillis();
        return "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";
    }  

    @Async
    public void task1() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(1000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }  

    @Async
    public void task2() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(2000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
    @Async
    public void task3() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(3000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
} 

main函数运行spirngboot项目,启动完成后浏览器访问:

http://localhost:8080/

控制台:

task1任务耗时:1012ms  

task2任务耗时:2009ms  

task3任务耗时:3004ms  

等了一段浏览器时候输出入下:

task任务总耗时:6002ms   

异步并没有执行!

难道是代码写错了?反复检查了好几遍,并没有发现什么明显错误,想起spring对@Transactional注解时也有类似问题,spring扫描时具有@Transactional注解方法的类时,是生成一个代理类,由代理类去开启关闭事务,而在同一个类中,方法调用是在类体内执行的,spring无法截获这个方法调用。

豁然开朗,将异步任务单独放到一个类中,调整代码入下:

Controller

@RequestMapping("")
@RestController
public class AsyncTaskController {  

    @Autowired
    private AsyncTask asyncTask;  

    @RequestMapping("")
    public String doTask() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        asyncTask.task1();
        asyncTask.task2();
        asyncTask.task3();
        long currentTimeMillis1 = System.currentTimeMillis();
        return "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";  

    }
}  

异步任务类

@Component
public class AsyncTask {  

    @Async
    public void task1() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(1000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }  

    @Async
    public void task2() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(2000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
    @Async
    public void task3() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(3000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
}  

控制台:

task1任务耗时:1012ms
task2任务耗时:2009ms
task3任务耗时:3004ms  

访问浏览器结果入下:

task任务总耗时:19ms

异步调用成功!

如何知道三个异步任务什么时候执行完,执行的结果怎样呢?可以采用添加Fature回调方式判断

代码入下:

异步任务类

@Component
public class AsyncTask {  

    @Async
    public Future<String> task1() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(1000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
        return new AsyncResult<String>("task1执行完毕");
    }  

    @Async
    public Future<String> task2() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(2000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
        return new AsyncResult<String>("task2执行完毕");
    }
    @Async
    public Future<String> task3() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(3000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
        return new AsyncResult<String>("task3执行完毕");
    }
}  

Controller

@RequestMapping("")
@RestController
public class AsyncTaskController {  

    @Autowired
    private AsyncTask asyncTask;  

    @RequestMapping("")
    public String doTask() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Future<String> task1 = asyncTask.task1();
        Future<String> task2 = asyncTask.task2();
        Future<String> task3 = asyncTask.task3();
        String result = null;
        for (;;) {
            if(task1.isDone() && task2.isDone() && task3.isDone()) {
                // 三个任务都调用完成,退出循环等待
                break;
            }
            Thread.sleep(1000);
        }
        long currentTimeMillis1 = System.currentTimeMillis();
        result = "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";
        return result;
    }
}  

控制台输出:

task1任务耗时:1000ms
task2任务耗时:2001ms
task3任务耗时:3001ms  

浏览器输出:

<span style="font-family:Simsun;font-size:14px;">task任务总耗时:4015ms</span>  

异步调用成功,并且在所有任务都完成时程序才返回了结果!

原文地址:https://www.cnblogs.com/shamo89/p/9095380.html

时间: 2024-08-29 03:37:58

springboot+async异步接口实现和调用的相关文章

SpringBoot @Async 异步处理业务逻辑和发短信逻辑

有个业务场景,业务数据审核通过后需要给用户发短信,发短信过程比较耗时,可能需要几秒甚至十几秒,因此使用异步发短信 使用了注解@Async来实现: 1.SpringApplication启用注解@EnableAsync @SpringBootApplication @ImportResource(locations = { "classpath:/spring/spring-*.xml" }) @EnableTransactionManagement(proxyTargetClass=t

SpringBoot中异步请求和异步调用(看这一篇就够了)

一.SpringBoot中异步请求的使用 1.异步请求与同步请求 特点: 可以先释放容器分配给请求的线程与相关资源,减轻系统负担,释放了容器所分配线程的请求,其响应将被延后,可以在耗时处理完成(例如长时间的运算)时再对客户端进行响应.一句话:增加了服务器对客户端请求的吞吐量(实际生产上我们用的比较少,如果并发请求量很大的情况下,我们会通过nginx把请求负载到集群服务的各个节点上来分摊请求压力,当然还可以通过消息队列来做请求的缓冲). 2.异步请求的实现 方式一:Servlet方式实现异步请求

EF异步改造之路~第二回 让DbContextRepository去实现异步接口

上一讲中,我们定义了三个异步操作接口,这回我们将对它进行实现,而有一个基础知识需要大家清楚,那就是实现接口的方式,一般我们使用默认的方式(隐式实现),这种方法实现的接口方式均为public,即它可以脱离接口,而直接通过类对象去访问,而当一个类继承多个接口,而这些接口中都有相同的方法时,我们就需要显示实现接口了,显示实现的接口成员只能通过接口实例去访问它,今天我们对DbContextRepository的改造就用到了这个特性. 基本关键字 async:用来标识这个方法为异步方法 await:用在异

SpringBoot下支付宝接口的使用

SpringBoot下支付宝接口的使用 前期准备: 参考之前写过的 支付宝接口引入servlet版本 Jar包引入: <!-- 支付宝 --> <dependency> <groupId>net.guerlab</groupId> <artifactId>sdk-alipay-starter</artifactId> <version>${alipay.version}</version> </depen

使用spring的@Async异步执行方法

应用场景: 1.某些耗时较长的而用户不需要等待该方法的处理结果 2.某些耗时较长的方法,后面的程序不需要用到这个方法的处理结果时 在spring的配置文件中加入对异步执行的支持 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.spri

异步服务之间的调用方式

本文为原作,转载请发自原文出处 http://www.cnblogs.com/jermmy/p/6752950.html,谢谢合作! 对与异步服务之间的调用方式LZ只使用了future和callback两种方式,其实异步服务之间的调用有以下几种 1.oneway oneway 是一种只管发送而不管结果的交互方式,不关心服务方的请求结果如何,属于一种单向的通知 2.future 多线程获取数据以及异步交互获取数据使用callable和future的组合是多服务中经常用到的,该接口在juc包中,ca

NodeJS中常见异步接口定义(get、post、jsonp)

越来越多的人在使用nodeJS,作为一门服务端语言,我们不可避免的要写异步接口(ajax和jsonp).再次强调ajax和jsonp是两个概念,但是由于jquery的封装,使这两种异步接口的调用方式,看起来比较相近,但在底层差别还是比较大的(本文只写服务端的实现). 为了便于讲解我使用express框架来运行我的demo.并分别讲解如何获取参数,并返回结果.本文相当于一个基础篇,只写了一些常见的应用场景.漏掉一些复杂的场景,还望提醒. 一.Ajax——post请求 之所以先从post开始,是因为

Async异步编程入门示例

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace AsyncDemo 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 Console.WriteLine("异步方法测试开始!&quo

表格存储新手指南:Java SDK异步接口的使用

原文地址 本篇文章主要会介绍下表格存储的Java SDK提供的异步接口,如何使用以及应用场景. 为什么需要异步? 异步提供了一个non-blocking, event-driven的编程模型,能够将系统不同层级的模块进行层次化的解耦,能够利用多核并行执行任务,提高性能. 现如今,一个大型的系统,系统级调优的最关键一步,就是异步化.异步化最常改造的是远程RPC或者数据库访问部分,表格存储作为一个底层数据库产品,需要提供异步接口来适应这个潮流. 在表格存储内部,我们也有一些使用异步来优化系统的例子,