本文介绍了如何正确应对来自ListenableFuture番石榴来异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我所提供的两种方法,同步和异步为我们的客户库。他们可以拨打他们觉得哪种方法最适合他们的目的。


  • executeSynchronous() - 等待,直到我有一个结果,返回结果

  • executeAsynchronous() - 返回一个未来如果需要其他的事情完成后立即可以加工,

他们将通过其拥有的用户ID在它DataKey对象。我们将找出对用户ID调用哪台机器的基础。因此,我们将使用AsyncRestTemplate进行HTTP调用的URL,然后发送响应返回给他们基础上,无论是成功还是失败。

下面是我的界面:

 公共接口的客户端{
    //同步
    公共DataResponse executeSync(最终DataKey键);    //异步
    公共未来< D​​ataResponse> executeAsync(最终DataKey键);
}

和下面是我的实现:

 公共类DataClient实现IClient {    //这是否必须是最终的?
    私人最终AsyncRestTemplate restTemplate =新AsyncRestTemplate();    @覆盖
    公共DataResponse executeSync(最终DataKey键){
        未来< D​​ataResponse> responseFuture = executeAsync(键);
        DataResponse响应=无效;
        尝试{
            响应= responseFuture.get(keys.getTimeout(),TimeUnit.Milliseconds);
        }赶上(CancellationException E){
            //在这里做什么?
        }赶上(InterruptedException的E){
            //是对付这种InterruptedException的正确方法?
            抛出新的RuntimeException(中断,E);
        }赶上(为ExecutionException E){
            //你是什么意思为ExecutionException?我们又该如何面对呢?
            DataLogging.logErrors(e.getCause(),DataErrorEnum.ERROR_CLIENT,密钥);
            响应=新DataResponse(NULL,DataErrorEnum.ERROR_CLIENT,DataStatusEnum.ERROR);
        }赶上(TimeoutException异常五){
            DataLogging.logErrors(e.getCause(),DataErrorEnum.TIMEOUT_ON_CLIENT,密钥);
            响应=新DataResponse(NULL,DataErrorEnum.TIMEOUT_ON_CLIENT,DataStatusEnum.ERROR);
        }        返回响应;
    }    @覆盖
    公共未来< D​​ataResponse> executeAsync(最终DataKey键){
        最后SettableFuture< D​​ataResponse> responseFuture = SettableFuture.create();
        restTemplate.exchange(createURL(键),HttpMethod.GET,keys.getEntity(),为String.class).addCallback(
                新ListenableFutureCallback< ResponseEntity<串GT;>(){
                    @覆盖
                    公共无效的onSuccess(ResponseEntity<串GT;的结果){
                        responseFuture.set(新DataResponse(result.getBody(),DataErrorEnum.OK,
                                DataStatusEnum.SUCCESS));
                    }                    @覆盖
                    公共无效onFailure处(Throwable的前){
                        DataLogging.logErrors(例如,DataErrorEnum.ERROR_SERVER,键);
                        responseFuture.set(新DataResponse(NULL,DataErrorEnum.ERROR_CLIENT,
                                DataStatusEnum.ERROR));
                    }
                });        返回responseFuture;    }
}

现在我的问题是:


  • 如何妥善处理在 executeSync 的catch块异常?有CancellationException和TimeoutException异常有什么区别?也就是我们一般应与为ExecutionException 吗?

  • 难道我的DataKey在我的界面是最终的?如果我在executeAsync执行删除最后一个变量,然后我得到的编译错误为无法引用非最终变量键在不同的方法中定义的内部类中。

  • 这是我的 executeAsync 方法使用ListenableFutureCallback的正确方法?或者有使用的?
  • 什么更好的方法

任何输入/建议,也欢迎对我的设计有同步和异步实现。


解决方案

我假设你使用Spring 4( AsyncRestTemplate )。在这种情况下ListenableFuture,你得到的是不是真的番石榴的ListenableFuture,但它的clone春天。反正你应该处理异常相同的方式,你处理与标准未来的例外。

回答您的问题:

It doesn't (in this case), but this is a good practice as in general it makes object less mutable simplifying reasoning about it's behaviour.

CancellationException will be thrown if task is cancelled (either via Future#cancel or ExecutorService#shutdownNow). It cannot happen in your case as only you have references to Future and (implicitly via private AsyncRestTemplate) ExecutorService used by execute queries. So

throw new AssertionError("executeAsync task couldn't be cancelled", e);

In Future#get call you've specified timeout. TimeoutException will be thrown if result is still not available after keys.getTimeout() milliseconds.

In this case no. InterruptedException will be thrown when client's thread is interrupted. You don't own that thread so you should propagate InterruptedException (i.e. declare executeSync(DataKey keys) throws InterruptedException). If for some reason you cannot change signature of the method then at least restore interrupted flag (Thread.currentThread().interrupt()) before throwing RuntimeException.

ExecutionException means that code submitted to ExecutorService as Callable/Runnable threw exception during execution. In your case ExecutionException will never be thrown because you return SettableFuture with value set in both onSuccess and onFailure callbacks, so you can throw AssertionError in the catch block. There is no general strategy of response to ExecutionException.

It must be final in executeAsync implementation because you reference it from anonymous class (onFailure callback);

Don't see anything wrong with it.

Some advices:

  1. Consider making thread pool for async client configurable.

By default AsyncRestTemplate uses SimpleAsyncTaskExecutor which creates new thread for each request. This may be not suitable for all your clients. Note that if you follow this advice response to CancellationException must be different as client now can have reference to ExecutorService: throwing RuntimeException should be fine.

  1. Describe in (java)doc thread pool used by default!

  2. I would split sync and async versions.

  3. I think that using sync RestTemplate and implementing async version by means of sync version would simplify implementation.

  4. Consider returning more flexible ListenableFuture instead of plain Future (using SettableListenableFuture instead of SettableFuture).

这篇关于如何正确应对来自ListenableFuture番石榴来异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-15 23:31