您现在的位置是:亿华云 > IT科技

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

亿华云2025-10-04 02:53:46【IT科技】9人已围观

简介环境:springboot2.3.9.RELEASE经常会遇到在项目中调用第三方接口的情景,你是如何调用的呢?同步?异步?场景:假设下单业务流程如下步骤:1、查询用户信息。2、查询库存信息。3、查询活

 环境:springboot2.3.9.RELEASE

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

场景:

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

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对象有点相像。站群服务器

很赞哦!(43)