У меня есть библиотека, в которой я предоставил два метода, синхронизацию и асинхронность для нашего клиента. Они могут называть тот метод, который, по их мнению, подходит для их целей.
- executeSynchronous() - ждет, пока у меня не будет результата, вернет результат.
- executeAsynchronous() - немедленно возвращает Будущее, которое может быть обработано после выполнения других действий, если это необходимо.
Они передадут объект DataKey, в котором есть идентификатор пользователя. И мы выясним, какую машину вызывать на основе идентификатора пользователя. Таким образом, мы сделаем http-обращение к URL-адресу с использованием AsyncRestTemplate, а затем отправим ответ на их вопрос о том, успешно ли он или нет.
Ниже мой интерфейс:
public interface Client {
// for synchronous
public DataResponse executeSync(final DataKey key);
// for asynchronous
public Future<DataResponse> executeAsync(final DataKey key);
}
И ниже моя реализация:
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;
}
}
Теперь мой вопрос:
- Как правильно обрабатывать исключения в блоке catch
executeSync
? Есть ли разница между CancellationException и TimeoutException? Также, что мы должны делать сExecutionException
в целом? - Должен ли мой DataKey быть окончательным в моем интерфейсе? Если я удаляю конечную переменную в моей реализации executeAsync, тогда я получаю ошибку компиляции как
Cannot refer to a non-final variable keys inside an inner class defined in a different method
. - Это правильный способ использования ListenableFutureCallback в моем методе
executeAsync
? Или есть лучший способ использовать это?
Любые входы/предложения также приветствуются в моем дизайне для реализации синхронизации и асинхронности.