当前位置:首页 >探索 >SpringBoot项目中异步调用接口方式知多少? 步调可编排任务执行

SpringBoot项目中异步调用接口方式知多少? 步调可编排任务执行

2024-06-28 16:39:31 [百科] 来源:避面尹邢网

SpringBoot项目中异步调用接口方式知多少?

作者:Springboot实战案例锦集 开发 前端 CompletableFuture提供了非常强大的项目异步编程方法,可同步,中异可异步,步调可编排任务执行,用接异步通过回调的口方方式执行。该对象很多的式知一些方法与前端JavaScript中的Promise对象有点相像。


环境:springboot2.5.12

SpringBoot项目中异步调用接口方式知多少? 步调可编排任务执行

经常会遇到在项目中调用第三方接口的多少情景,你是项目如何调用的呢?同步?异步?

SpringBoot项目中异步调用接口方式知多少? 步调可编排任务执行

场景:

SpringBoot项目中异步调用接口方式知多少? 步调可编排任务执行

假设下单业务流程如下步骤:

1、查询用户信息。中异

2、步调查询库存信息。用接

3、口方查询活动信息(折扣)。式知

1、多少同步顺序调用

public boolean createOrder() {   long start = System.currentTimeMillis() ;  String userResult = restTemplate.getForObject("http://localhost:8080/users/{ 1}",项目 String.class, new Object[] { 1}) ;  String storageResult = restTemplate.getForObject("http://localhost:8080/storage/{ 1}", String.class, new Object[] { 1}) ;  String discountResult = restTemplate.getForObject("http://localhost:8080/discount/{ 1}", String.class, new Object[] { 1}) ;  // 这里合并请求结果处理  System.out.println(Arrays.toString(new String[] { userResult, storageResult, discountResult})) ;  System.out.println("传统方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;  return true ;}@GetMapping("/create")public Object create() {   return os.createOrder() ;}

调用结果:

图片图片

接口一个一个调用,非常耗时。

2、多线程(Callable+Future)

public boolean createOrder2() {   long start = System.currentTimeMillis() ;  Callable<String> userCallable = () -> {     return restTemplate.getForObject("http://localhost:8080/users/{ 1}", String.class, new Object[] { 1}) ;  } ;  Callable<String> storageCallable = () -> {     return restTemplate.getForObject("http://localhost:8080/storage/{ 1}", String.class, new Object[] { 1}) ;  } ;  Callable<String> discountCallable = () -> {     return restTemplate.getForObject("http://localhost:8080/discount/{ 1}", String.class, new Object[] { 1}) ;  } ;  FutureTask<String> userTask = new FutureTask<>(userCallable) ;  FutureTask<String> storageTask = new FutureTask<>(storageCallable) ;  FutureTask<String> discountTask = new FutureTask<>(discountCallable) ;  new Thread(userTask).start() ;  new Thread(storageTask).start() ;  new Thread(discountTask).start() ;  try {     String userResult = userTask.get() ;    String storageResult = storageTask.get() ;    String discountResult = discountTask.get() ;    // 这里合并请求结果处理    System.out.println(Arrays.toString(new String[] { userResult, storageResult, discountResult})) ;  } catch (InterruptedException | ExecutionException e) {     e.printStackTrace();  }  System.out.println("多线程方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;  return true ;}

调用结果:

图片图片

这次耗时少了,性能明显提升了。但在项目中我们一般是禁止直接创建线程的,如果这是个高并发的接口,那么我们的程序很可能出现OOM的错误。

3、线程池(Callable+Future)防止内存溢出风险

ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000)) ;  public boolean createOrder3() {   long start = System.currentTimeMillis() ;  List<Future<String>> results = new ArrayList<>(3) ;  results.add(pool.submit(() -> {       return restTemplate.getForObject("http://localhost:8080/users/{ 1}", String.class, new Object[] { 1}) ;  })) ;  results.add(pool.submit(() -> {       return restTemplate.getForObject("http://localhost:8080/storage/{ 1}", String.class, new Object[] { 1}) ;  })) ;  results.add(pool.submit(() -> {     return restTemplate.getForObject("http://localhost:8080/discount/{ 1}", String.class, new Object[] { 1}) ;  })) ;  for (int i = 0, size = results.size(); i < size; i++) {     try {       System.out.println(results.get(i).get()) ;    } catch (InterruptedException | ExecutionException e) {       e.printStackTrace();    }  }  System.out.println("线程池方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;  return true ;}

调用结果:

图片图片

耗时和上一个基本一致,通过Future的方式有一个问题就是只能一个一个的取值,只有当前的返回数据了后才会继续往下执行。如果有其它的任务执行完,那没有轮到它也必须等待。

4、CompletionService(异步任务与使用已完成任务的结果分离),submit提交任务,take获取已经完成的任务,不用按照submit的顺序获取结果。

public boolean createOrder4() {   long start = System.currentTimeMillis() ;  CompletionService<String> cs = new ExecutorCompletionService<>(pool) ;  cs.submit(() -> {     return restTemplate.getForObject("http://localhost:8080/users/{ 1}", String.class, new Object[] { 1}) ;  }) ;  cs.submit(() -> {     return restTemplate.getForObject("http://localhost:8080/storage/{ 1}", String.class, new Object[] { 1}) ;  }) ;  cs.submit(() -> {     return restTemplate.getForObject("http://localhost:8080/discount/{ 1}", String.class, new Object[] { 1}) ;  }) ;  for (int i = 2 ; i >=0; i--) {     try {       System.out.println(cs.take().get()) ;    } catch (InterruptedException | ExecutionException e) {       e.printStackTrace();    }  }  System.out.println("CompletionService方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;  return true ;}

调用结果:

图片图片

通过CompletionService方式不管任务添加的顺序是什么,只要通过take方法就能获取执行完的结果,如果没有任务执行完,take方法会阻塞。

5、CompletableFuture(异步任务编排),JDK1.8

public boolean createOrder5() {   long start = System.currentTimeMillis() ;  CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> {     return restTemplate.getForObject("http://localhost:8080/users/{ 1}", String.class, new Object[] { 1}) ;  }) ;      CompletableFuture<String> storageFuture = CompletableFuture.supplyAsync(() -> {     return restTemplate.getForObject("http://localhost:8080/storage/{ 1}", String.class, new Object[] { 1}) ;  }) ;      CompletableFuture<String> discountFuture = CompletableFuture.supplyAsync(() -> {     return restTemplate.getForObject("http://localhost:8080/discount/{ 1}", String.class, new Object[] { 1});  }) ;  CompletableFuture<List<String>> result = CompletableFuture      .allOf(userFuture, storageFuture, discountFuture)      .thenApply((Void) -> {         List<String> datas = new ArrayList<>() ;        try {           datas.add(userFuture.get()) ;          datas.add(storageFuture.get()) ;          datas.add(discountFuture.get()) ;        } catch (InterruptedException | ExecutionException e) {           e.printStackTrace();        }        return datas ;      }).exceptionally(e -> {         e.printStackTrace() ;        return null ;      }) ;  try {     System.out.println(result.get()) ;  } catch (InterruptedException | ExecutionException e1) {     e1.printStackTrace();  }  System.out.println("CompletableFuture方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;  return true ;}

调用结果:

图片图片

CompletableFuture提供了非常强大的异步编程方法,可同步,可异步,可编排任务执行,异步通过回调的方式执行。该对象很多的一些方法与前端JavaScript中的Promise对象有点相像。

完毕!!!


责任编辑:武晓燕 来源: Spring全家桶实战案例源码 异步编程方法

(责任编辑:休闲)

    推荐文章
    热点阅读