如何在Java中以同步方式处理异步回调?

如何在Java中以同步方式处理异步回调?,java,multithreading,asynchronous,architecture,integration-patterns,Java,Multithreading,Asynchronous,Architecture,Integration Patterns,我有一个与建筑相关的问题。这是一个与语言无关的问题,但由于我来自Java背景,如果有人用Java的方式指导我,对我来说会更容易 基本上,我正在编写的中间件与基于SOAP的第三方服务进行通信。调用是异步的——在某种程度上,当调用服务时,它返回一个响应01——处理;表示第三方已成功接收请求。在原始SOAP请求中,每次都必须提交一个回调URL,第三方实际会在其中发送结果。因此,调用特定的服务实际上并不会立即返回结果;结果在中间件中的单独HTTP端点中接收 现在在我们的前端,我们不想让用户体验复杂化。我

我有一个与建筑相关的问题。这是一个与语言无关的问题,但由于我来自Java背景,如果有人用Java的方式指导我,对我来说会更容易

基本上,我正在编写的中间件与基于SOAP的第三方服务进行通信。调用是异步的——在某种程度上,当调用服务时,它返回一个响应01——处理;表示第三方已成功接收请求。在原始SOAP请求中,每次都必须提交一个回调URL,第三方实际会在其中发送结果。因此,调用特定的服务实际上并不会立即返回结果;结果在中间件中的单独HTTP端点中接收

现在在我们的前端,我们不想让用户体验复杂化。我们希望用户调用中间件函数(通过菜单项/按钮),并立即得到结果;把脏活留给中间件去做

请注意,从前端调用的中间件函数(比如X())和第三方推送结果的中间件端点URL(称为Y)是完全独立的。X()必须以某种方式等待,然后获取Y中获取的结果,然后将结果返回到前端

我如何构建一个健壮的解决方案来实现上述行为?
这幅画完美地描绘了我的情况。任何建议都将不胜感激。

那么这样做到底有什么问题?您只需创建一个API(中间件),它在第三方返回处理结果之前不会返回响应。前端将请求发送到X(),X()通过向Y()发送请求来处理该请求,然后继续轮询Y()以查看结果何时就绪,然后X()从Y()获取结果并将其发送回前端。就像一个门面

关于使用第三方服务的一些问题,你不应该控制,你应该考虑。首先,您需要实现某种断路器或超时。因为第三方服务可能会挂起并且永远不会处理结果(或者处理它们的时间太长以至于等待没有意义)。此外,你应该考虑一些有意义的方法来保持站点运行,即使第三方服务不可用或者更新了API,或者其他东西阻止你使用它。
最后还有最后一个想法。为什么要使已经实现的东西异步同步?这样做可能是因为它可能需要时间。长时间阻塞前端等待结果会让用户体验不愉快,用户界面没有响应。通常更好的做法是坚持异步请求,向用户显示他们正在处理的请求,但同时让他们做其他事情

这个问题更多的是关于集成模式,而不是关于多线程。但是,可以使用异步调用和观察者模式的组合来编排同一应用程序/JVM中的请求:

最好使用一个示例(利用您的Java知识)来实现这一点。检查以下试图复制您的场景的简单组件:

第三方服务:它公开一个操作,该操作返回一个相关ID并开始长时间运行的执行

class ExternalService {
    public String send() {
        return UUID.randomUUID().toString();
    }
}
面向客户的服务:它接收请求,调用第三方服务,然后在向结果接收者注册后等待响应:

class RequestProcessor {
    public Object submitRequest() {
        String correlationId = new ExternalService().send();

        return new ResultReceiver().register(correlationId).join();
    }
}
结果接收方:向第三方服务公开操作,并维护内部关联注册表:

class ResultReceiver {

    Map<String, CompletableFuture<Object>> subscribers;

    CompletableFuture<Object> register(String responseId) {
        CompletableFuture<Object> future = new CompletableFuture<Object>();
        this.subscribers.put(responseId, future);

        return future;
    }

    public void externalResponse(String responseId, Object result) {
        this.subscribers.get(responseId).complete(result);
    }
}

结果接收中间件如何将结果发送到原始请求目标中间件?x()和y()在同一个服务/应用程序中是不同的操作吗?未来和承诺。@ErnestKiwele:x()和y()都是同一个中间件的一部分。X()接收来自FE的请求,并将异步调用发送给第三方。然后第三方处理请求并将结果(可以是post调用)返回给Y()(这是一个端点URL,也在中间件中)。我同意,让异步调用同步一开始听起来并不正确,但这样想想,并不是所有的功能都要花很长时间才能完成。第三方应该为简单任务保留一些同步调用,但他们没有。那么,我们为什么要让我们的客户为此受苦呢?一些琐碎的任务需要立即响应——我们无法实际显示“您的请求正在处理”。每次都请等。这就是问题所在。我就是这么说的。这就像门面设计模式——简化更复杂的界面。你可以这样做,但要花些时间考虑会出什么问题。例如,至少为这些调用添加一些超时,如果它们没有在合理的时间内完成,则返回错误。但是,如果我按原样对待异步功能,则会出现问题-我无法理解它。假设我让前端异步调用X()。然后,X()将调用第三方,第三方返回处理,X()将此返回到前端。同时,3party处理结果并将其返回给Y。现在,没有人在听Y,x()已经将初始响应返回给前端。必须引入一些监听器,以便Y将数据返回到实际的客户端。顺便说一句,我所说的前端是指移动应用程序。是的,对于移动应用程序来说,最好是使用监听器,而不是阻塞接口。因为有人可能会认为它崩溃了:)但是的,你需要添加某种侦听器或在一段时间后轮询,或者保持一些连接打开,以获得另一个线程或其他结果。在你的示例中,
Map subscribers
是否应该初始化和静态?@gbdcool它当然必须初始化,但不需要是静态的(这取决于
new ResultReceiver().register(correlationId)
    .get(10000, TimeUnit.SECONDS);