【问题标题】:Best practices to retrieve CompletableFuture lists of different types检索不同类型的 CompletableFuture 列表的最佳实践
【发布时间】:2020-08-20 12:17:58
【问题描述】:

我想从数据库中检索不同类型的数据,并在 Spring Boot 服务的 HTTP 结果中返回给用户。因为每个数据库检索都需要大量时间,所以我使用 CompletableFuture 异步调用这些数据库。与同步执行此操作相比,我拥有的模式有效并节省了时间,但我觉得它可以而且应该以更简洁的方式布局。

我编辑了代码以将类型更改为“PartA”、“PartB”、“PartC”,但这就是它的显示方式。目前,该服务接受不同类型的列表(PartA、PartB、PartC),创建每个列表的 Completable Future 类型,调用它自己的调用 DB 的 CompletableFuture 方法,为每个列表构建一个 generic 的 CompleteableFutures 列表type,“获取”通用列表,然后将每个 Future 列表的所有内容添加到传递给服务的列表中。

Service 方法的编码方式如下:

Service.java:

    public void metadata(final List<PartA> partAs,final List<PartB> partBs,final List<PartC> partCs,
                         String prefix,String base,String suffix) throws Exception {
        try {
            CompletableFuture<List<PartA>> futurePartAs = partACompletableFuture(prefix,base,suffix).thenApply(list -> {
                logger.info("PartA here");
                return list;
            });
            CompletableFuture<List<PartB>> futurePartBs = partBCompletableFuture(prefix,base,suffix).thenApply(list -> {
                logger.info("PartBs here");
                return list;
            });
            CompletableFuture<List<PartC>> futurePartCs = partCCompletableFuture(prefix,base,suffix).thenApply(list -> {
                logger.info("PartCs here");
                return list;
            });
            CompletableFuture<?> combinedFuture = CompletableFuture.allOf(CompletableFuture.allOf(futurePartAs, futurePartBs, futurePartCs));
            combinedFuture.get();
            partAs.addAll(futurePartAs.get());
            partBs.addAll(futurePartBs.get());
            partCs.addAll(futurePartCs.get());
        } catch (Exception e) {
            logger.error("Exception: ", e);
            throw e;
        }
    }


    @Async("asyncExecutor")
    public CompletableFuture<List<PartA>> partACompletableFuture(String prefix,String base,String suffix) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                logger.info("start PartA");
                return getPartAs(prefix,base,suffix);
            } catch (Exception e) {
                logger.error("Exception: ", e);
                throw e;
            }
        });
    }
    @Async("asyncExecutor")
    public CompletableFuture<List<PartB>> partBCompletableFuture(String prefix,String base,String suffix) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                logger.info("start B");
                return getPartBs(prefix,base,suffix);
            } catch (Exception e) {
                logger.error("Exception: ", e);
                throw e;
            }
        });
    }
    @Async("asyncExecutor")
    public CompletableFuture<List<PartC>> partCCompletableFuture(String prefix,String base,String suffix) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                logger.info("start PartC");
                return getPartCs(prefix,base,suffix);
            } catch (Exception e) {
                logger.error("Exception: ", e);
                throw e;
            }
        });
    }

如果您希望查看控制器和响应类型:

Controller.java

    @GetMapping(value="/parts/metadata",produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<MetadataResponse> metadata (@ApiParam(name="prefix",value = "Prefix value for a part",required = false)
                                                         @RequestParam(required=false) String prefix,
                                                              @ApiParam(name="base",value = "Base value for a part",required= true)
                                                         @RequestParam String base,
                                                              @ApiParam(name="suffix",value = "Suffix value for a part",required=false)
                                                         @RequestParam(required=false) @NotBlank  String suffix ) throws Exception {
        final List<PartA> partAs = new ArrayList<>();
        final List<PartB> partBs = new ArrayList<>();
        final List<PartC> partCs = new ArrayList<>();
        service.metadata(partAs,partBs,partCs,prefix,base,suffix);
        MetadataResponse.MetadataResponseResult res = MetadataResponse.MetadataResponseResult.builder()
                .partAs(partAs)
                .partBs(partBs)
                .partCs(partCs)
                .build();
        return ResponseEntity.ok(MetadataResponse.result(res, MetadataResponse.class));
    }

MetadataResponse.java

@ApiModel(value = "MetadataResponse", parent = BaseBodyResponse.class, description = "Part A, B, C")
public class MetadataResponse extends BaseBodyResponse<MetadataResponse.MetadataResponseResult> {
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @ApiModel(value = "MetadataResponseResult", description = "This Model holds Part As, Bs, Cs")
    public static class MetadataResponseResult {
        List<PartA> partAs;
        List<PartB> partBs;
        List<PartC> partCs;
    }

}

【问题讨论】:

    标签: java spring asynchronous completable-future


    【解决方案1】:
    • 我不明白为什么在这种情况下您需要将所有这些列表作为参数传递:public void metadata(final List&lt;PartA&gt; partAs,final List&lt;PartB&gt; partBs,final List&lt;PartC&gt; partCs, String prefix,String base,String suffix) throws Exception 您可以修改此方法以返回您已经拥有的 MetadataResponseResult 类并直接使用 ComparableFutures 中的列表
    • 我会删除 thenApply 方法,因为您只是记录了一条语句,实际上并没有更改结果。
    • 您可以使用一种方法接收供应商作为参数,而不是使用三种方法(partACompletableFuturepartABCompletableFuturepartCCompletableFuture)。
            @Async("asyncExecutor")
            public <T> CompletableFuture<T> partCompletableFuture(Supplier<T> supplier) {
                return CompletableFuture.supplyAsync(() -> {
                    try {
                        logger.info("start Part");
                        return supplier.get();
                    } catch (Exception e) {
                        logger.error("Exception: ", e);
                        throw e;
                    }
                });
            }
    

    之后你可以这样使用它:

    CompletableFuture<List<PartA>> futurePartAs = partCompletableFuture(() -> 
                                         getPartAs(prefix,base,suffix));
    

    它应该更干净。希望这有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 1970-01-01
      • 2023-04-03
      • 2010-09-27
      • 2020-02-01
      • 1970-01-01
      相关资源
      最近更新 更多