繁体   English   中英

将CompletableFuture与@Async一起使用将为Spring Boot API返回空响应

[英]Using CompletableFuture with @Async returns an empty response for spring boot API

这是我的控制器。 我使用邮递员来测试它是否正常工作,但是我收到了一个空的答复。 我用@EnableAsync在应用程序配置和@Async的服务。 如果我在服务层上删除@Async ,它可以工作,但不会异步运行。

@ApiOperation(value = "search person by passing search criteria event/title/role/host/is_current", response = ElasticSearchResultData.class)
@RequestMapping(value = "/async2/searchPerson", produces = "application/json", method = RequestMethod.POST)
public @ResponseBody CompletableFuture<ElasticSearchResultData> searchPersonAsync2(@RequestBody SearchCriteriaTo criteriaForDivNetFolderTo,
        HttpServletRequest request, HttpServletResponse response){
    LOGGER.info("searchPerson controller start");
    SearchCriteria searchCriteria = criteriaForDivNetFolderTo.getSearchCriteria();
    if (Util.isNull(searchCriteria)) 
        throw new IllegalArgumentException("search criteria should not be null.");

    try {
        CompletableFuture<ElasticSearchResultData> searchPerson = cubService.searchPersonAsync2(criteriaForDivNetFolderTo);
        ObjectMapper mapper = new ObjectMapper();
        LOGGER.info("search Person "+mapper.writeValueAsString(searchPerson));
        return searchPerson;
    } catch (Exception e) {
        LOGGER.error("Exception in searchPersonAsync controller "+e.getMessage());
    }
    return null;
}

服务

@Async
@Override
public CompletableFuture<ElasticSearchResultData> searchPersonAsync2(SearchCriteriaTo searchCriteriaForDivNetFolderTo) {
   Long start = System.currentTimeMillis();
   LOGGER.info(":in searchPerson");
   CompletableFuture<ElasticSearchResultData> completableFuture = new CompletableFuture<>();
   ElasticSearchResultData searchResultData = null;
   SearchCriteria searchCriteria = searchCriteriaForDivNetFolderTo.getSearchCriteria();
   try {
        LOGGER.info("************ Started searchPerson by criteria ************");
        StringBuilder url = new StringBuilder();
        url.append(equilarSearchEngineApiUrl)
        .append(focusCompanySearchUrl)
        .append("/")
        .append("searchPerson")
        .append("?view=").append(VIEW_ALL)
        .append("&isProcessing=true");

        LOGGER.debug("Calling equilar search engine for focused company search, URL : " + url);
        LOGGER.info(searchCriteria.toString());
        String output = null;
        if (redisEnable != null && redisEnable) {
            output = cacheDao.getDataFromRestApi(url.toString(), RequestMethod.POST.name(), searchCriteria);
        } else {
            output = Util.getDataFromRestApi(url.toString(), RequestMethod.POST.name(), searchCriteria);
        }
        if (!Util.isEmptyString(output)) {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            searchResultData = objectMapper.readValue(output,
                            objectMapper.getTypeFactory().constructType(ElasticSearchResultData.class));
        }
        List<PersonSearchDetails> newPersonDetails = new ArrayList<PersonSearchDetails>();
        if (!Util.isNull(searchResultData) && !Util.isNullOrEmptyCollection(searchResultData.getPersonDetails())
                && !Util.isNullOrEmptyCollection(searchCriteriaForDivNetFolderTo.getNetworkFoldersData())) {
            for (PersonSearchDetails personDetail : searchResultData.getPersonDetails()) {
                String logoUrl = null;
                if(!Util.isNull(searchCriteria.getTargetFolderId())){
                    List<DiversityNetworkFolderTo> filteredFolderTos = searchCriteriaForDivNetFolderTo
                            .getNetworkFoldersData()
                            .stream()
                            .filter(folder -> folder.getId()
                            .longValue() == searchCriteria
                            .getTargetFolderId())
                            .collect(Collectors.toList());
                    logoUrl = getLogoUrl(personDetail.getPersonId(),
                            filteredFolderTos);
                } else {
                    logoUrl = getLogoUrl(personDetail.getPersonId(),
                            searchCriteriaForDivNetFolderTo.getNetworkFoldersData());
                }
                personDetail.setLogoUrl(logoUrl);
                newPersonDetails.add(personDetail);
            }
            searchResultData.setPersonDetails(newPersonDetails);
        }
        completableFuture.complete(searchResultData);
        return completableFuture;
    } catch (Exception e) {
        completableFuture.completeExceptionally(e);
        LOGGER.error(
                " ************** Error in proccessing searchPerson by criteria ************** " + e.getMessage());
    }
    Long end = System.currentTimeMillis();
    LOGGER.info(TIME_DURATION+(end - start)+"ms");
    return null;
}

最好阅读有关异步处理的更多信息。 通常, javadocs是一个不错的开始!

如果您真的想从Future方法获得结果,则需要等待。

CompletableFuture API中有一个方法public T get()方法来等待创建结果,并在完成后返回结果。

如果您的工作是在数据库中搜索结果,然后返回它-您仍然必须等待它异步在这里并没有太大帮助。 如果您必须同时进行多项操作(例如,对数据库的调用,Web服务和其他操作),这将对您有所帮助,那么您可以创建一系列期货并等待所有这些完成。

或者,假设您正在创建POST方法,因此您可以快速验证输入并发送到数据库异步存储,同时快速将响应返回给UI,并希望您的异步方法将在另一个线程中完成并且不会返回任何错误到UI。

当您知道自己在做什么时,但在使用前先考虑是否真正需要它时,这是一种很棒的技术。

“修复”此问题的简短方法是:

CompletableFuture<ElasticSearchResultData> searchPerson = cubService.searchPersonAsync2(criteriaForDivNetFolderTo);
ElasticSearchResultData result = searchPerson.get();
ObjectMapper mapper = new ObjectMapper();
LOGGER.info("search Person "+mapper.writeValueAsString(result));
return result;

(并且显然更改方法的返回签名)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM