Spring boot 如何从@Async注释的方法引发异常

Spring boot 如何从@Async注释的方法引发异常,spring-boot,asynchronous,spring-async,Spring Boot,Asynchronous,Spring Async,我有两个模块,一个从rest模板调用另一个。 (管理员调用notifServer) notifServer有一个用@Async注释的方法。我想在该方法中抛出一个异常,但是管理员得到响应太快,并且无法在admin中捕获异常方法 我是spring和@Async进程的新成员。我已经尝试将响应主体从NotifServer映射到CCompletableFuture.class。 但我仍然没有得到错误响应 此代码来自管理员 ResponseEntity response = fcmRestTemplate.

我有两个模块,一个从rest模板调用另一个。 (管理员调用notifServer) notifServer有一个用
@Async
注释的方法。我想在该方法中抛出一个异常,但是管理员得到响应太快,并且无法在admin中捕获异常方法

我是spring和@Async进程的新成员。我已经尝试将响应主体从NotifServer映射到C
CompletableFuture.class
。 但我仍然没有得到错误响应

此代码来自管理员

ResponseEntity response = fcmRestTemplate.exchange(nsUrl + "/fcm/admin/" + bulkFcmId, HttpMethod.POST,
                    HttpEntityUtils.getHttpEntity(moduleCode), CompletableFuture.class);
            if (response.getStatusCode() != HttpStatus.CREATED && response.getStatusCode() != HttpStatus.ACCEPTED) {
                String errorMessage = ErrorResourceUtil.getErrorMessage((HashMap) response.getBody(),"Unable to send fcm");
                setStatusToFailedByBulkFcmId(bulkFcmId);
                throw new ClientException(errorMessage);
            }
现在这是来自NotifServer的

JobExecution jobExecution = jobLauncher
                    .run(importJob, new JobParametersBuilder()
                    .addString("fullPathFileName", TMP_DIR)
                    .addString("batch_fcm_id", String.valueOf(id))
                    .addLong("time",System.currentTimeMillis())
                    .toJobParameters());
            if(jobExecution.getStepExecutions().stream().map(StepExecution::getStatus).findFirst().get().equals(BatchStatus.ABANDONED)){
             throw new ClientException("INVALID CSV");
这是用@Async注释的

那么,有没有一种方法可以让我在Admin中的响应体中捕获客户端异常

编辑 这是notifServer的API

@ResponseStatus(HttpStatus.CREATED)
    @PostMapping(value = "/admin/{bulkFcmId}")
    public void pushFCMByAdmin(@PathVariable Long bulkFcmId) {
        fcmService.sendFcmByAdmin(bulkFcmId, AuthUtil.getCurrentUser());
    }

然后sendFcmByAdmin具有@Async注释

在下面的代码中,您能否将返回类型设置为业务对象而不是CompletableFuture.class。由于您将CompletableFuture.class作为参数传递给exchange,因此它需要CompletableFuture.class类型的响应返回值

ResponseEntity response = fcmRestTemplate.exchange(nsUrl + "/fcm/admin/" + bulkFcmId, HttpMethod.POST,
                        HttpEntityUtils.getHttpEntity(moduleCode), CompletableFuture.class);
                if (response.getStatusCode() != HttpStatus.CREATED && response.getStatusCode() != HttpStatus.ACCEPTED) {
                    String errorMessage = ErrorResourceUtil.getErrorMessage((HashMap) response.getBody(),"Unable to send fcm");
                    setStatusToFailedByBulkFcmId(bulkFcmId);
                    throw new ClientException(errorMessage);
                }
您可以尝试按如下方式创建它,而不是传递可完成的未来:

使用异步方法在admin中调用rest模板:

@Async
public CompletableFuture<List<BusinessObject>> getResponseAsynchronously(String value) {
    String url = "https://restendpoint.eu/rest/v2/lang/" + value + "?fields=name";
    BusinessObject[] response = restTemplate.getForObject(url, Country[].class);
    return CompletableFuture.completedFuture(Arrays.asList(response));
}
@Async
公共CompletableFuture getResponseAsynchronously(字符串值){
字符串url=”https://restendpoint.eu/rest/v2/lang/“+value+”?字段=名称”;
BusinessObject[]response=restTemplate.getForObject(url,国家[].class);
返回CompletableFuture.completedFuture(Arrays.asList(response));
}
然后在控制器中读取CompletableFuture,如下所示:

@GetMapping("")
public List<String> getAllDataFromRestCall() throws Throwable {

    CompletableFuture<List<BusinessObject>> businessObjectsFuture = countryClient.getResponseAsynchronously("fr");
    List<String> europeanFrenchSpeakingCountries;

            try {
                europeanFrenchSpeakingCountries = new ArrayList<>(businessObjectsFuture
                .get()
                .stream()
                .map(Country::getName)
                .collect(Collectors.toList()));

     } catch (Throwable e) {
       throw e.getCause();
     }

   return europeanFrenchSpeakingCountries;
}
@GetMapping(“”)
public List getAllDataFromRestCall()抛出可丢弃的{
CompletableFuture businessObjectsFuture=countryClient.getResponseAsynchronously(“fr”);
列出欧洲、法国和欧洲的高峰国家;
试一试{
europeanFrenchSpeakingCountries=新阵列列表(businessObjectsFuture
.get()
.stream()
.map(国家::getName)
.collect(Collectors.toList());
}捕获(可丢弃的e){
抛出e.getCause();
}
返回欧洲、法国、巅峰国家;
}

在下面的代码中,您是否可以将返回类型设置为业务对象而不是CompletableFuture.class。因为您将CompletableFuture.class作为参数传递给exchange,所以它需要CompletableFuture.class类型的响应返回值

ResponseEntity response = fcmRestTemplate.exchange(nsUrl + "/fcm/admin/" + bulkFcmId, HttpMethod.POST,
                        HttpEntityUtils.getHttpEntity(moduleCode), CompletableFuture.class);
                if (response.getStatusCode() != HttpStatus.CREATED && response.getStatusCode() != HttpStatus.ACCEPTED) {
                    String errorMessage = ErrorResourceUtil.getErrorMessage((HashMap) response.getBody(),"Unable to send fcm");
                    setStatusToFailedByBulkFcmId(bulkFcmId);
                    throw new ClientException(errorMessage);
                }
您可以尝试按如下方式创建它,而不是传递可完成的未来:

使用异步方法在admin中调用rest模板:

@Async
public CompletableFuture<List<BusinessObject>> getResponseAsynchronously(String value) {
    String url = "https://restendpoint.eu/rest/v2/lang/" + value + "?fields=name";
    BusinessObject[] response = restTemplate.getForObject(url, Country[].class);
    return CompletableFuture.completedFuture(Arrays.asList(response));
}
@Async
公共CompletableFuture getResponseAsynchronously(字符串值){
字符串url=”https://restendpoint.eu/rest/v2/lang/“+value+”?字段=名称”;
BusinessObject[]response=restTemplate.getForObject(url,国家[].class);
返回CompletableFuture.completedFuture(Arrays.asList(response));
}
然后在控制器中读取CompletableFuture,如下所示:

@GetMapping("")
public List<String> getAllDataFromRestCall() throws Throwable {

    CompletableFuture<List<BusinessObject>> businessObjectsFuture = countryClient.getResponseAsynchronously("fr");
    List<String> europeanFrenchSpeakingCountries;

            try {
                europeanFrenchSpeakingCountries = new ArrayList<>(businessObjectsFuture
                .get()
                .stream()
                .map(Country::getName)
                .collect(Collectors.toList()));

     } catch (Throwable e) {
       throw e.getCause();
     }

   return europeanFrenchSpeakingCountries;
}
@GetMapping(“”)
public List getAllDataFromRestCall()抛出可丢弃的{
CompletableFuture businessObjectsFuture=countryClient.getResponseAsynchronously(“fr”);
列出欧洲、法国和欧洲的高峰国家;
试一试{
europeanFrenchSpeakingCountries=新阵列列表(businessObjectsFuture
.get()
.stream()
.map(国家::getName)
.collect(Collectors.toList());
}捕获(可丢弃的e){
抛出e.getCause();
}
返回欧洲、法国、巅峰国家;
}

我猜NotifServer上的RESTAPI没有等待异步调用完成并立即返回。你能用NotifServer的完整API代码更新帖子吗?我用NotifServer的控制器编辑过,sendFcmByAdmin是一个void方法,它调用批处理作业和pushFcm方法。sendFcmByAdmin有@Async?是的,先生!该方法有@async,我猜NotifServer上的RESTAPI没有等待异步调用完成并立即返回。你能用NotifServer的完整API代码更新帖子吗?我用NotifServer的控制器编辑过,sendFcmByAdmin是一个void方法,它调用批处理作业和pushFcm方法。sendFcmByAdmin有@Async?是的,先生!该方法有@AsyncI尝试过,但基本上是同步的,所以使用@AsyncI有什么意义?您可以提供更多细节,比如stacktrace,以便我们可以更深入地分析问题。因此,即使在使用completable future调用该方法之后,请求也会被同步触发?我尝试过,但基本上是同步的,所以使用@Async有什么意义?请提供更多细节,如stacktrace,以便我们可以更深入地分析问题。那么,即使在使用completable future调用该方法之后,请求也会被同步触发?