用于处理Java中的异步响应的设计模式

我从类似的问答中读到答案

如何在JAVA中创建异步HTTP请求? | 异步编程设计模式 |
AsyncTask Android – 设计模式和返回值

我看到很多解决方案,但没有一个真的让我满意。

听众的方式

捕获结果后,处理将在onResult方法中实现。

public interface GeolocationListener { public void onResult(Address[] addresses); public void onError(Exception e); } 

这个解决方案并不能让我满意,因为我想在main方法中处理结果。 我讨厌这个接口,因为当返回响应时,它会在onResult中处理,导致处理链,无法返回“main”方法。

servlet的方式

 public class SignGuestbookServlet extends HttpServlet { public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { // ... resp.sendRedirect("/guestbook.jsp"); } } 

没有公开的Java代码调用servlet。 所有配置都在web.xml中完成

我想要的方式

等待这样的回复

 Response a = getResponse(); // wait until the response is received, do not go further // process Response b = getResponse(); // wait until the response is received, do not go further process(a,b); 

是否有设计模式来处理异步请求并等待上面的响应? 其他方式比听众。 请不要图书馆或框架。

编辑感谢到目前为止的回复。 我没有给你全面的图片所以我暴露了Geolocation类我开始实现。 我不知道如何实现该方法。 有人能说“怎么样”? 他(或她)还必须实现侦听器以检索结果

 private Address getFullAddress (String text, AddressListener listener, ... ){ // new Geolocation(text, listener, options).start() // implements Geolocation.GeolocationListener // how to return the Address from the onResult ? } 

异步代码始终可以同步。 最简单/最原始的方法是进行异步调用,然后输入一个只停留当前线程的while循环,直到值返回。

编辑:将异步回调转换为同步代码的代码 – 再次,粗略的实现:

 import java.util.concurrent.*; public class MakeAsynchronousCodeSynchronous { public static void main(String[] args) throws Exception { final Listener listener = new Listener(); Runnable delayedTask = new Runnable() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { throw new IllegalStateException("Shouldn't be interrupted", e); } listener.onResult(123); } }; System.out.println(System.currentTimeMillis() + ": Starting task"); Executors.newSingleThreadExecutor().submit(delayedTask); System.out.println(System.currentTimeMillis() + ": Waiting for task to finish"); while (!listener.isDone()) { Thread.sleep(100); } System.out.println(System.currentTimeMillis() + ": Task finished; result=" + listener.getResult()); } private static class Listener { private Integer result; private boolean done; public void onResult(Integer result) { this.result = result; this.done = true; } public boolean isDone() { return done; } public Integer getResult() { return result; } } } 

你也可以按照hakon的回答推荐使用CountDownLatch。 它基本上会做同样的事情。 我还建议你熟悉java.util.concurrent包,以便更好地管理线程。 最后,仅仅因为你做到这一点并不是一个好主意。 如果您正在使用基于异步回调的框架,那么学习如何有效地使用框架比尝试颠覆它可能要好得多。

首先,您不应该拒绝您讨论的前两种方法。 人们使用这些技术有很好的理由,你应该尝试学习它们而不是创造新技术。

否则,你应该看看java.util.concurrent :

 ExecutorService es = Executors.newFixedThreadPool(2); ... Future responseA = es.submit(responseGetter); Future responseB = es.submit(responseGetter); process(responseA.get(), responseB.get()); 

其中responseGetter的类型为Callable (您必须实现方法public Response call() )。

CountDownLatch可以帮到你吗? 在main方法中,您调用getResponse,然后调用countDownLatch.await()。 将倒计数锁存器传递给getResponse方法,然后在getResponse中倒计时getResponse结果:

 CountDownLatch latch = new CountDownLatch(1); Response a = getResponse(latch); latch.await(); latch = new CountDownLatch(1); Response b = getResponse(latch); latch.await(); process(a, b); 

一旦异步部分返回结果,你的getResponse就需要调用latch.countDown()。

例如:

 public Response getResponse(CountDownLatch latch) { someAsychBloc(final CountDownLatch latch) { do work latch.countDown(); } } 

从本质上讲,无论如何,你都需要一种“倾听者”。 这是因为你不知道什么时候你的返回消息会回来,如果有的话(这是异步处理的缺点之一……如果没有得到返回消息该怎么办)。

因此,您需要实现一个等待事件的侦听器(即,它将被要处理的返回消息所推动)。

或者你可以通过在你的服务上“轮询”(或拉取)响应区域来查看返回消息是否存在,从而对其进行混合。

所以它真正归结为你是否想要更多的“拉”或“推”方法来检索消息。

SCA(服务组件体系结构)框架可能需要考虑,但根据您的工作情况,它也可能过度。 但需要考虑的事情。

编辑:

我刚刚在Java SE 6 Javadocs中发现这可能会有所帮助。 接口CompletionService抽象你关心的东西 – >异步工作。 我建议你看看。

如果您想在Web应用程序中使用页面流,则必须以Web方式处理:在会话中存储一些数据,或者cookie或隐藏字段等。

据我所知,你试图解决的问题不是来自异步,而是来自无状态的http protocole。

此致,Stéphane