我假设你正在使用 Spring 4 (异步休息模板)。在这种情况下,你得到的 ListenableFuture 并不是真正的 Guava 的 ListenableFuture,而是 Spring 中的克隆。无论如何,您应该以与处理标准 Future 中的异常相同的方式处理异常。
对您问题的答复:
// does this have to be final? private final AsyncRestTemplate
restTemplate = new AsyncRestTemplate();
它不会(在本例中),但这是一个很好的实践,因为一般来说它使对象的可变性更小,从而简化了对其行为的推理。
catch (CancellationException e) {
// what to do here?
}
如果任务被取消(通过 Future#cancel 或 ExecutorService#shutdownNow),将抛出 CancellationException。在您的情况下不会发生这种情况,因为只有您引用了执行查询所使用的 Future 和(隐式通过私有 AsyncRestTemplate)ExecutorService。所以
throw new AssertionError("executeAsync task couldn't be cancelled", e);
CancellationException 和 CancellationException 之间有什么区别
超时异常?
在 Future#get 调用中您指定了超时。如果在keys.getTimeout()毫秒后结果仍然不可用,则会抛出TimeoutException。
catch (InterruptedException e) {
// is this right way to deal with InterruptedException?
throw new RuntimeException("Interrupted", e);
}
在这种情况下没有。当以下情况时会抛出InterruptedExceptionclient's线程被中断。您不拥有该线程,因此您应该传播 InterruptedException (即声明executeSync(DataKey keys) throws InterruptedException
)。如果由于某种原因您无法更改方法的签名,那么至少恢复中断标志(Thread.currentThread().interrupt()
) 在抛出 RuntimeException 之前。
catch (ExecutionException e) {
// what do you mean by ExecutionException? And how should we deal with this?
DataLogging.logErrors(e.getCause(), DataErrorEnum.ERROR_CLIENT, keys);
response = new DataResponse(null, DataErrorEnum.ERROR_CLIENT, DataStatusEnum.ERROR);
}
ExecutionException 意味着作为 Callable/Runnable 提交给 ExecutorService 的代码在执行过程中抛出异常。在您的情况下, ExecutionException 永远不会被抛出,因为您返回 SettableFuture 并在 onSuccess 和 onFailure 回调中设置了值,因此您可以在 catch 块中抛出 AssertionError 。对于 ExecutionException 没有通用的响应策略。
我的 DataKey 在我的界面中必须是最终的吗?
它在executeAsync实现中必须是final的,因为您从匿名类(onFailure回调)引用它;
这是在我的executeAsync 方法中使用ListenableFutureCallback 的正确方法吗?或者有没有更好的方法来使用它?
没看出有什么问题。
一些建议:
- 考虑使异步客户端的线程池可配置。
默认情况下 AsyncRestTemplate 使用简单异步任务执行器它为每个请求创建新线程。这可能并不适合您的所有客户。请注意,如果您遵循此建议,对 CancellationException 的响应必须有所不同,因为客户端现在可以引用 ExecutorService:抛出 RuntimeException 应该没问题。
在(java)doc中描述了默认使用的线程池!
我会拆分同步和异步版本。
我认为使用同步 RestTemplate 并通过同步版本实现异步版本会简化实现。
考虑返回更灵活的 ListenableFuture 而不是普通的 Future (使用可设置可监听未来而不是 SettableFuture)。