代码之家  ›  专栏  ›  技术社区  ›  john

如何使用回调实现异步调用?

  •  1
  • john  · 技术社区  · 9 年前

    我需要创建一个库,其中包含同步和异步方法。

    我的图书馆的核心逻辑-

    客户将使用我们的图书馆,他们将通过 DataKey 生成器对象。然后,我们将使用 数据密钥 对象,并通过执行该URL对其进行HTTP客户端调用,在我们将响应作为JSON字符串返回后,我们将通过创建 DataResponse 对象

    我将使用同步和异步方法。一些客户会拨打 executeSynchronous 方法来获得相同的功能,一些客户将调用我们的 executeAsynchronous 方法和 执行同步 方法,它们将调用 future.get 在代码本身中。

    下面是我的界面-

    public interface Client {
    
        // for synchronous
        public DataResponse executeSynchronous(DataKey dataKey);
    
        // for asynchronous
        public Future<DataResponse> executeAsynchronous(DataKey dataKey);
    }
    

    下面是我的 数据响应 类-

    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;
        }
    }
    

    问题陈述:-

    如上所述,一些客户会致电 执行同步 方法获取他们传递的用户id的数据 数据密钥 对象,一些客户会致电 执行同步 方法 数据密钥 对象,但在后一种情况下,它们会这样做 未来获取 在他们的代码库中。

    如果你看到我的 执行同步 方法,我正在做 未来获取 呼叫后 执行同步 方法,如果有 TimeoutException ,然后我使用 PotoLogging 类,该类在我们公司中是特定的,日志将转到此处的其他服务,我们使用该服务在仪表板上查看所有错误日志。这主要取决于我们如何使用什么名称记录它,以便我们可以在仪表板中看到这些名称。

    现在问题是我们公司的客户也可以打电话 执行同步 方法,但这意味着,他们会做到 未来获取 这也会导致 超时异常 在他们的代码中,但我不能强迫他们以我现在这样做的方式进行日志记录。所以我的问题是-如果有任何方法,我可以得到回调吗 超时异常 如果有人打电话,我可以这样记录 执行同步 我的库在其代码库中的方法-

    PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
    

    我需要这样做,这样我的图书馆才能登录 超时异常 在我们公司的工具中,以我们想要的方式进行记录。否则,我需要告诉每个客户这样做,以便我们可以在仪表板中看到它。如何从异步调用中获取回调,并仍然利用异步的所有特性?

    最好的方法是什么?

    1 回复  |  直到 9 年前
        1
  •  2
  •   Sotirios Delimanolis    9 年前

    Future 只是一个界面。提供包装服务返回的实例的实现。使其将所有调用委托给实际 将来 并用适当的try-catch块包装这些调用。

    Future<DataResponse> wrapper = new Future<DataResponse>() {
        private final Future<DataResponse> delegate = future;
    
        @Override
        public boolean cancel(boolean mayInterruptIfRunning) {
            return delegate.cancel(mayInterruptIfRunning);
        }
    
        @Override
        public boolean isCancelled() {
            return delegate.isCancelled();
        }
    
        @Override
        public boolean isDone() {
            return delegate.isDone();
        }
    
        @Override
        public DataResponse get() throws InterruptedException, ExecutionException {
            DataResponse dataResponse = null;
            try {
                delegate.get();
            } catch (TimeoutException ex) {
                PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
                dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
            }
            return dataResponse;
        }
    
        @Override
        public DataResponse get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            DataResponse dataResponse = null;
            try {
                delegate.get(timeout, unit);
            } catch (TimeoutException ex) {
                PotoLogging.logErrors(ex, DataErrorEnum.TIMEOUT_ON_CLIENT, dataKey);
                dataResponse = new DataResponse(null, DataErrorEnum.TIMEOUT_ON_CLIENT, DataStatusEnum.ERROR);
            }
            return dataResponse;
        }
    };
    return wrapper;