Java 如何将异步HTTP请求抽象为同步请求

Java 如何将异步HTTP请求抽象为同步请求,java,rest,concurrency,rx-java,Java,Rest,Concurrency,Rx Java,我有一个行为“异步”的第三方RESTAPI服务;正如在中一样,请求使用中间响应进行响应,中间响应由具有中间响应相关器的回调进行补充 回调几乎立即通过“回调URL”返回 我正试图设计一种解决方案,一种适配器来调用这个资源,就好像它是“同步的”,因为处理回调很麻烦,特别是当我需要通过同一第三方将连续的请求串行批处理到其他类似的API时。基本上,我想抽象绿色部分,以便调用方只获得完全回调、错误或超时异常。 我的研究重点是使用RxJava,但我不知道如何用反应式编程的原理来解决这个问题(我的理解是有限

我有一个行为“异步”的第三方RESTAPI服务;正如在中一样,请求使用中间响应进行响应,中间响应由具有中间响应相关器的回调进行补充

回调几乎立即通过“回调URL”返回

我正试图设计一种解决方案,一种适配器来调用这个资源,就好像它是“同步的”,因为处理回调很麻烦,特别是当我需要通过同一第三方将连续的请求串行批处理到其他类似的API时。基本上,我想抽象绿色部分,以便调用方只获得完全回调、错误或超时异常。

我的研究重点是使用RxJava,但我不知道如何用反应式编程的原理来解决这个问题(我的理解是有限的)

设计注意事项:

  • 将相关器持久化到数据存储以供以后在回调时查找是不可取的,因为这很昂贵
  • 回调的等待策略正常,因为回调的响应时间小于1秒

  • 如何使用
    CompletableFuture
    Observable Observator
    模式来等待回调并返回给调用方?

    考虑使用
    CountDownLatch
    让主线程等待工作线程处理完第三方API。工作者获取回调,以便知道请求何时进行、何时完成、何时超时、何时出错等

    下面是一个粗略的模拟:

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ThreadLocalRandom;
    
    public class TreatAsSync {
    
        public static void main(String[] args) {
            TreatAsSync app = new TreatAsSync();
            app.call();
        }
    
        private void call() {
            RestClient restClient = new RestClient();
            Request request = new Request();
            Response response = restClient.call(request);
            System.out.println("Response was: " + response);
        }
    
        private class Request {
    
        }
    
        private class Response {
            private final boolean error;
            private final boolean timedOut;
            private final String result;
    
            public Response(boolean error, boolean timedOut, String result) {
                this.error = error;
                this.timedOut = timedOut;
                this.result = result;
            }
    
            public String toString() {
                return "error:" + error + ", timedOut: " + timedOut + ", result: " + result;
            }
        }
    
        private class ResponseWrapper {
            private Response response;
    
            public Response getResponse() {
                return response;
            }
    
            public void setRespose(Response response) {
                this.response = response;
            }
        }
    
        private class RestClient {
    
            public Response call(Request request) {
                ResponseWrapper wrapper = new ResponseWrapper();
                CountDownLatch latch = new CountDownLatch(1);
    
                ThirdPartyRunner runner = new ThirdPartyRunner(request, wrapper, latch);
                new Thread(runner).start();
    
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
    
                return wrapper.getResponse();
            }
        }
    
        private interface ThirdPartyCallBack {
            public void onProgress(Response response);
            public void onComplete(Response response);
            public void onTimeOut(Response response);
            public void onError(Response response);
        }
    
        private class ThirdPartyRunner implements ThirdPartyCallBack, Runnable {
            private final Request request;
            private final ResponseWrapper wrapper;
            private final CountDownLatch latch;
    
            public ThirdPartyRunner(Request request, ResponseWrapper wrapper, CountDownLatch latch) {
                this.request = request;
                this.wrapper = wrapper;
                this.latch = latch;
            }
    
            @Override
            public void onProgress(Response response) {
                System.out.println("some progress was made...");
            }
    
            @Override
            public void onComplete(Response response) {
                System.out.println("request completed");
                finished(response);
            }
    
            @Override
            public void onTimeOut(Response response) {
                System.out.println("request timed out");
                finished(response);
            }
    
            @Override
            public void onError(Response response) {
                System.out.println("request had an error");
                finished(response);
            }
    
            private void finished(Response response) {
                wrapper.setRespose(response);
                latch.countDown();
            }
    
            @Override
            public void run() {
                try {
                    callThirdParty();
                } catch (Exception e) {
                    finished(new Response(true, false, e.getMessage()));
                }
            }
    
            private void callThirdParty() {
                // simulate api.call(request, this);
                for (int i = 0; i < ThreadLocalRandom.current().nextInt(10) + 1; i++) {
                    onProgress(new Response(false, false, "in progress"));
                }
    
                switch (ThreadLocalRandom.current().nextInt(3)) {
                case 0:
                    onComplete(new Response(false, false, "done"));
                    break;
    
                case 1:
                    onTimeOut(new Response(false, true, "hello?"));
                    break;
    
                case 2:
                    onError(new Response(true, false, "uh oh!"));
                    break;
                }
            }
        }
    
    }
    
    import java.util.concurrent.CountDownLatch;
    导入java.util.concurrent.ThreadLocalRandom;
    公共课助理{
    公共静态void main(字符串[]args){
    TreatAsSync app=新的TreatAsSync();
    app.call();
    }
    私有无效调用(){
    RestClient RestClient=new RestClient();
    请求=新请求();
    Response=restClient.call(请求);
    System.out.println(“响应为:”+响应);
    }
    私有类请求{
    }
    私有类响应{
    私有最终布尔错误;
    私有最终布尔timedOut;
    私有最终字符串结果;
    公共响应(布尔错误、布尔timedOut、字符串结果){
    this.error=错误;
    this.timedOut=timedOut;
    this.result=结果;
    }
    公共字符串toString(){
    返回“error:+error+”,timedOut:+timedOut+”,result:+result;
    }
    }
    私有类响应包装器{
    私人回应;
    公共响应getResponse(){
    返回响应;
    }
    公共无效设置响应(响应){
    这个。反应=反应;
    }
    }
    私有类RestClient{
    公共响应呼叫(请求){
    ResponseWrapper=新ResponseWrapper();
    CountDownLatch闩锁=新的CountDownLatch(1);
    第三方运行程序=新的第三方运行程序(请求、包装、锁存);
    新线程(runner.start();
    试一试{
    satch.wait();
    }捕捉(中断异常e){
    抛出新的运行时异常(e);
    }
    返回wrapper.getResponse();
    }
    }
    专用接口第三方回调{
    公共进展(响应);
    公共空间未完成(响应);
    公共无效超时(响应);
    公共无效报告人(响应);
    }
    私有类ThirdPartyRunner实现ThirdPartyCallBack,可运行{
    私人最终请求;
    私有最终响应包装器;
    私有最终倒计时闩锁;
    公共第三方运行程序(请求请求、响应包装器、倒计时闩锁){
    this.request=请求;
    this.wrapper=包装器;
    this.latch=闩锁;
    }
    @凌驾
    公共进度(响应){
    System.out.println(“取得了一些进展…”);
    }
    @凌驾
    公共空间未完成(响应){
    System.out.println(“请求完成”);
    完成(应答);
    }
    @凌驾
    public void onTimeOut(响应){
    System.out.println(“请求超时”);
    完成(应答);
    }
    @凌驾
    公共无效申报人(回复){
    System.out.println(“请求有错误”);
    完成(应答);
    }
    私有无效已完成(响应){
    setRespose(响应);
    倒计时();
    }
    @凌驾
    公开募捐{
    试一试{
    调用第三方();
    }捕获(例外e){
    已完成(新响应(true、false,例如getMessage());
    }
    }
    私人无效呼叫第三方(){
    //模拟api.call(请求,this);
    对于(int i=0;i
    如果您有:

    public ImmediateResponse asynchCall(Callback callback) throws ImmediateException {...}
    
    其中,
    回调
    如下所示:

    interface Callback {
        void onSuccess(EventualResponse eventualResponse);
        void onFailure(Exception e);
    }
    
    public static EventualResponse synchCall(long timeout, TimeUnit timeUnit)
            throws InterruptedException, TimeoutException, EventualException
    {
        CompletableFuture<EventualResponse> responseFuture = new CompletableFuture<>();
        Callback callback = new Callback() {
            public void onSuccess(EventualResponse response) { 
                responseFuture.complete(response); 
            }
            public void onFailure(Exception e) { 
                responseFuture.completeExceptionally(e); 
            }
        };
        try {
            /*ImmediateResponse immediateResponse = */asynchCall(callback); 
            // use immediateResponse if you need it
            return responseFuture.get(timeout, timeUnit);
        } catch (ImmediateException e) {
            throw new EventualException(e);
        } catch (ExecutionException ee) {
            throw new EventualException(ee.getCause());
        }
    }
    
    那么你想要的是这样的东西:

    interface Callback {
        void onSuccess(EventualResponse eventualResponse);
        void onFailure(Exception e);
    }
    
    public static EventualResponse synchCall(long timeout, TimeUnit timeUnit)
            throws InterruptedException, TimeoutException, EventualException
    {
        CompletableFuture<EventualResponse> responseFuture = new CompletableFuture<>();
        Callback callback = new Callback() {
            public void onSuccess(EventualResponse response) { 
                responseFuture.complete(response); 
            }
            public void onFailure(Exception e) { 
                responseFuture.completeExceptionally(e); 
            }
        };
        try {
            /*ImmediateResponse immediateResponse = */asynchCall(callback); 
            // use immediateResponse if you need it
            return responseFuture.get(timeout, timeUnit);
        } catch (ImmediateException e) {
            throw new EventualException(e);
        } catch (ExecutionException ee) {
            throw new EventualException(ee.getCause());
        }
    }
    
    publicstaticeventualresponse-synchCall(长超时,TimeUnit-TimeUnit)
    抛出InterruptedException、TimeoutException、EventualException