我对Java(我使用Java SE 7)和JVM并尝试使用以下命令编写异步控制器相当新:
我有一个组件,我的控制器委托一些具有异步部分的工作并返回一个ListenableFuture。理想情况下,我希望释放最初处理控制器响应的线程,因为我等待异步操作返回,因此需要异步控制器。
我正在考虑返回DeferredResponse - 将它与ListenableFuture联系起来似乎很容易 - 但我似乎无法找到任何资源来解释如何将响应传递回客户端DeferredResponse解析。
也许我并不完全了解异步控制器应该如何工作,但有人可以解释一旦DeferredResponse结算后响应如何返回给客户端?必须有一些线程能够完成发送响应的工作,对吗?
答案 0 :(得分:0)
我最近在最近编码的长轮询情况下使用了Spring的DeferredResponse。我相信,专注于回复用户的响应的“方式”并不是思考对象的正确方法。根据它的使用位置,它以与常规同步调用完全相同的方式向用户返回消息,这种方式只能以延迟的异步方式进行。同样,该对象没有定义或提出传递机制。只是一种将异步响应“插入”现有通道的方法。
根据您的查询,是的,它通过创建一个具有用户规范超时的线程来实现。如果代码在超时之前完成,则使用'setResult',该对象返回代码的结果。否则,如果超时在结果之前触发,则返回由用户设置的默认值。无论哪种方式,对象都不会返回任何内容(除了对象本身),直到调用其中一个机制。此外,必须丢弃该对象,因为它不能被重用。
在我的情况下,我使用HTTP请求/响应函数将返回的响应包装在DeferredResponse对象中,该对象将提供默认响应 - 从客户端请求另一个数据包,以便浏览器不会超时 - 如果计算正在处理的代码在超时之前没有返回。每当计算完成时,它将通过'setResult'函数调用发送响应。在这种情况下,两种情况都只是使用HTTP响应将数据包发送回用户。但是,在任何情况下,响应都不会立即返回给用户。
在实践中,该对象完美无缺,并允许我实施有效的长轮询机制。
以下是我的示例中的代码片段:
@RequestMapping(method = RequestMethod.POST, produces = "application/text")
@ResponseBody
// public DeferredResult<String> onMessage(@RequestBody String message, HttpSession session) {
public DeferredResult<String> onMessage(InputStream is, HttpSession session) {
String message = convertStreamToString(is);
// HttpSession session = null;
messageInfo info = getMessageInfo(message);
String state = info.getState();
String id = info.getCallID();
DeferredResult<String> futureMessage =
new DeferredResult<>(refreshIntervalSecs * msInSec, getRefreshJsonMessage(id));
if(state != null && id != null) {
if(state.equals("REFRESH")) {
// Cache response for future and "swallow" call as it is restocking call
LOG.info("Refresh received for call " + id);
synchronized (lock) {
boolean isReplaceable = callsMap.containsKey(id) && callsMap.get(id).isSetOrExpired();
if (isReplaceable)
callsMap.put(id, futureMessage);
else {
LOG.warning("Refresh packet arrived on a non-existent call");
futureMessage.setResult(getExitJsonMessage(id));
}
}
} else if (state.equals("NEW")){
// Store response for future and pass the call onto the processing logic
LOG.info("New long-poll call received with id " + id);
ClientSupport cs = clientSupportMap.get(session.getId());
if(cs == null) {
cs = new ClientSupport(this, session.getId());
clientSupportMap.put(session.getId(), cs);
}
callsMap.put(id, futureMessage);
// *** IMPORTANT ****
// This method sets up a separate thread to do work
cs.newCall(message);
}
} else {
LOG.warning("Invalid call information");
// Return value immediately when return is called
futureMessage.setResult("");
}
return futureMessage;
}