Мне нужно создать библиотеку, в которой у меня будут синхронные и асинхронные методы.Как реализовать асинхронный вызов с обратным вызовом?
Основной логика моей библиотеки -
Клиента будет использовать нашу библиотеку, и они будут называть его пропусканием DataKey
объекта строителя. Затем мы создадим URL-адрес с помощью этого объекта DataKey
и сделаем клиентский вызов HTTP с этим URL-адресом, выполнив его, и после того, как мы получим ответ в виде строки JSON, мы отправим эту JSON-строку нашему клиенту, поскольку он создает DataResponse
объект.
У меня будут синхронные и асинхронные методы. Некоторые клиенты вызовут метод executeSynchronous
, чтобы получить такую же функцию, и некоторый клиент будет называть наш метод executeAsynchronous
и с помощью метода executeAsynchronous
, они будут вызывать future.get
там, где сам код.
Ниже мой интерфейс -
public interface Client {
// for synchronous
public DataResponse executeSynchronous(DataKey dataKey);
// for asynchronous
public Future<DataResponse> executeAsynchronous(DataKey dataKey);
}
Ниже мой DataResponse
класс -
public class DataResponse {
private String response;
private DataErrorEnum error;
private DataStatusEnum status;
// constructor here
// and getters here
}
Ниже мой DataStatusEnum
класс -
public enum DataStatusEnum {
SUCCESS, ERROR;
}
Ниже мой DataErrorEnum
класс -
public enum DataErrorEnum {
NONE(200, "NONE", "Response is success."),
SERVER_DOWN(3145, "Server Down", "some long message here which can give more details."),
CLIENT_ERROR(3123, "Client Error", "some long message here which can give more details."),
TIMEOUT_ON_CLIENT(3187, "Client Timeout", "some long message here which can give more details.");
private final int code;
private final String status;
private final String description;
// constructor and getters here
}
И затем у меня есть мой DataClient
, который реализует вышеуказанный интерфейс Client
.
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate();
private ExecutorService service = Executors.newFixedThreadPool(10);
// for synchronous call
@Override
public DataResponse executeSynchronous(DataKey dataKey) {
DataResponse dataResponse = null;
try {
Future<String> future = executeAsynchronous(dataKey);
dataResponse = future.get(dataKey.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
//for asynchronous call
@Override
public Future<DataResponse> executeAsynchronous(DataKey dataKey) {
Future<DataResponse> future = null;
try {
Task task = new Task(dataKey, restTemplate);
future = executor.submit(task);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
}
return future;
}
}
Теперь ниже мой простой класс, который будет выполнять фактическую задачу -
public class Task implements Callable<DataResponse> {
private DataKey dataKey;
private RestTemplate restTemplate;
public Task(DataKey dataKey, RestTemplate restTemplate) {
this.dataKey = dataKey;
this.restTemplate = restTemplate;
}
@Override
public DataResponse call() throws Exception {
DataResponse dataResponse = null;
String response = null;
try {
String url = createURL();
response = restTemplate.getForObject(url, String.class);
// it is a successful response
dataResponse = new DataResponse(response, DataErrorEnum.NONE, DataStatusEnum.SUCCESS);
} catch (RestClientException ex) {
PotoLogging.logErrors(ex, DataErrorEnum.SERVER_DOWN, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.SERVER_DOWN, DataStatusEnum.ERROR);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, dataKey);
dataResponse = new DataResponse(null, DataErrorEnum.CLIENT_ERROR, DataStatusEnum.ERROR);
}
return dataResponse;
}
// create a URL by using dataKey object
private String createURL() {
String url = somecode;
return url;
}
}
Постановка задачи: -
Как я уже упоминал выше, некоторые клиенты будут вызывать executeSynchronous
метод, чтобы получить данные для этого идентификатора пользователя, которые они передают в объекте DataKey
, и некоторые клиенты вызовут метод executeAsynchronous
с объектом DataKey
, но в последнем случае они будут делать future.get
в их базе кода.
Если вы видите мой executeSynchronous
метод, я делаю future.get
после вызова executeAsynchronous
метода и если есть TimeoutException
, то я войти, используя PotoLogging
класс, который является специфичным в нашей компании, и что журналы будут идти в какой-то другой сервис здесь, который мы используем для просмотра всех журналов ошибок на панели управления. И в основном это зависит от того, как мы регистрируем его с именами, чтобы мы могли видеть эти имена в панели управления.
Теперь проблема клиента в нашей компании можно также назвать executeAsynchronous
метод, но это означает, что они будут делать future.get
в их кодовой базы, и что также может привести к TimeoutException
в своем коде, но я не могу заставить их войти так же, как Я делаю это.Так что мой вопрос - Есть ли способ, что я могу получить обратный вызов, если есть какие-либо TimeoutException
так, что я могу войти это так, если кто-то звонит executeAsynchronous
метод моей библиотеки в их базе кода -
PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
мне нужно для этого, чтобы моя библиотека могла регистрировать TimeoutException
в инструменте, который у нас есть в нашей компании, как мы этого хотим. Другой, я должен сказать каждому клиенту сделать это так, чтобы мы могли видеть его в нашей панели. Как я могу получить обратный вызов от асинхронного вызова и все еще использовать все возможности асинхронности?
Каков наилучший способ для этого?
Спасибо за ваше предложение. Я не могу понять, как использовать это с моей текущей настройкой или мне нужно что-то изменить в моем текущем проекте? Я никогда не работал с обратным вызовом и будущей реализацией, поэтому мне было трудно понять это. Если возможно, вы можете помочь мне понять, как я буду использовать это? – john
@david Вы делаете это в своем 'executeAsynchronous', беря' Future', возвращенный 'ExecutorService'. Вы завершаете этот экземпляр с помощью «обертки», указанной выше, и возвращаете этот экземпляр «wrapper». Обратите внимание, как анонимный класс в моем ответе имеет поле 'delegate', которое инициализируется вашим« будущим ». –