Java 如何正确处理未来上市番石榴的例外情况?
我有一个库,其中我为我们的客户提供了两种方法:同步和异步。他们可以调用任何他们认为适合自己目的的方法Java 如何正确处理未来上市番石榴的例外情况?,java,multithreading,asynchronous,guava,future,Java,Multithreading,Asynchronous,Guava,Future,我有一个库,其中我为我们的客户提供了两种方法:同步和异步。他们可以调用任何他们认为适合自己目的的方法 executeSynchronous()-等待得到结果,然后返回结果 executeAsynchronous()-立即返回一个Future,如果需要,可以在完成其他操作后处理该Future 它们将传递包含用户id的DataKey对象。我们将根据用户id确定要调用哪台机器。因此,我们将使用AsyncRestTemplate对url进行http调用,然后根据调用是否成功将响应发送回给他们 以下是
- executeSynchronous()-等待得到结果,然后返回结果
- executeAsynchronous()-立即返回一个Future,如果需要,可以在完成其他操作后处理该Future
public interface Client {
// for synchronous
public DataResponse executeSync(final DataKey key);
// for asynchronous
public Future<DataResponse> executeAsync(final DataKey key);
}
公共接口客户端{
//同步
公共数据响应executeSync(最终数据密钥);
//异步的
公共未来执行同步(最终数据密钥);
}
下面是我的实现:
public class DataClient implements IClient {
// does this have to be final?
private final AsyncRestTemplate restTemplate = new AsyncRestTemplate();
@Override
public DataResponse executeSync(final DataKey keys) {
Future<DataResponse> responseFuture = executeAsync(keys);
DataResponse response = null;
try {
response = responseFuture.get(keys.getTimeout(), TimeUnit.Milliseconds);
} catch (CancellationException e) {
// what to do here?
} catch (InterruptedException e) {
// is this right way to deal with InterruptedException?
throw new RuntimeException("Interrupted", e);
} 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);
} catch (TimeoutException e) {
DataLogging.logErrors(e.getCause(), DataErrorEnum.TIMEOUT_ON_CLIENT, keys);
response = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
}
return response;
}
@Override
public Future<DataResponse> executeAsync(final DataKey keys) {
final SettableFuture<DataResponse> responseFuture = SettableFuture.create();
restTemplate.exchange(createURL(keys), HttpMethod.GET, keys.getEntity(), String.class).addCallback(
new ListenableFutureCallback<ResponseEntity<String>>() {
@Override
public void onSuccess(ResponseEntity<String> result) {
responseFuture.set(new DataResponse(result.getBody(), DataErrorEnum.OK,
DataStatusEnum.SUCCESS));
}
@Override
public void onFailure(Throwable ex) {
DataLogging.logErrors(ex, DataErrorEnum.ERROR_SERVER, keys);
responseFuture.set(new DataResponse(null, DataErrorEnum.ERROR_CLIENT,
DataStatusEnum.ERROR));
}
});
return responseFuture;
}
}
公共类DataClient实现IClient{
//这必须是最终决定吗?
私有最终AsyncRestTemplate restTemplate=新AsyncRestTemplate();
@凌驾
公共DataResponse executeSync(最终数据密钥){
未来响应未来=执行同步(键);
DataResponse=null;
试一试{
response=responseFuture.get(key.getTimeout(),TimeUnit.ms);
}捕获(取消异常e){
//在这里做什么?
}捕捉(中断异常e){
//这是处理中断异常的正确方法吗?
抛出新的运行时异常(“中断”,e);
}捕获(执行例外){
//你说的死刑例外是什么意思?我们应该如何处理?
logErrors(例如getCause(),DataErrorEnum.ERROR\u客户端,键);
response=新的DataResponse(null,DataErrorEnum.ERROR\u客户端,DataStatusEnum.ERROR);
}捕获(超时异常e){
logErrors(例如,getCause(),客户端上的DataErrorEnum.TIMEOUT\u,键);
response=新的DataResponse(null,客户端上的DataErrorEnum.TIMEOUT,DataStatusEnum.ERROR);
}
返回响应;
}
@凌驾
公共未来执行同步(最终数据密钥){
final SettableFuture responseFuture=SettableFuture.create();
restemplate.exchange(createURL(keys)、HttpMethod.GET、keys.getEntity()、String.class).addCallback(
新建ListenableFutureCallback(){
@凌驾
成功时公共无效(响应结果){
responseFuture.set(新的DataResponse(result.getBody()、DataErrorEnum.OK、,
DataStatusEnum.SUCCESS);
}
@凌驾
失效时的公共无效(可丢弃的ex){
logErrors(例如,DataErrorEnum.ERROR_服务器,密钥);
responseFuture.set(新的DataResponse(null,DataErrorEnum.ERROR\u客户端,
DataStatusEnum.ERROR);
}
});
回报与未来;
}
}
现在我的问题是:
- 如何正确处理
的catch块中的异常?CancellationException和TimeoutException之间有什么区别吗?另外,我们通常应该如何处理executeSync
执行异常
- 在我的接口中,我的数据键必须是最终的吗?如果在executeAsync实现中删除final变量,则会出现编译错误,因为
无法引用在不同方法中定义的内部类中的非final变量键
- 这是在我的
方法中使用ListenableFutureCallback的正确方法吗?还是有更好的方法来使用它executeAsync
在我的设计中,对于同步和异步实现,也欢迎任何输入/建议。我假设您使用的是Spring 4()。在这种情况下,你得到的未来不是番石榴的未来,而是春天的克隆。无论如何,您应该像处理标准将来的异常一样处理异常 回答你的问题: 它不会(在本例中),但这是一个很好的实践,因为在一般情况下,它会减少对象的易变性,从而简化对其行为的推理 如果取消任务(通过Future#cancel或ExecutorService#shutdownNow)将引发CancellationException。这种情况在您的情况下不会发生,因为只有您对execute查询使用的Future和(通过私有AsyncRestTemplate隐式地)EXECUTERService有引用。所以
throw new AssertionError("executeAsync task couldn't be cancelled", e);
CancellationException和
超时异常
将来#接到指定超时的来电。如果在keys.getTimeout()毫秒后结果仍然不可用,则将引发TimeoutException
在这种情况下,当客户端的线程被中断时,不会抛出InterruptedException。您不拥有该线程,因此应该传播InterruptedException(即,declareexecuteSync(数据键键)抛出InterruptedException
)。如果由于某种原因无法更改方法的签名,则在引发RuntimeException之前,至少恢复中断标志(Thread.currentThread().interrupt()
)
ExecutionException是指作为Callable/Runnable提交给ExecutorService的代码在执行期间引发异常。在您的情况下,永远不会抛出ExecutionException,因为您在onSuccess和onFailure回调中返回SettableFuture并设置值,因此您可以在catch块中抛出AssertionError。没有针对执行例外的一般策略
在我的接口中,我的数据键必须是最终的吗
它在executeAsync实现中必须是final,因为您从匿名类(onFailure回调)引用它
这是r吗
catch (CancellationException e) {
// what to do here?
}
throw new AssertionError("executeAsync task couldn't be cancelled", e);
catch (InterruptedException e) {
// is this right way to deal with InterruptedException?
throw new RuntimeException("Interrupted", e);
}
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);
}