我正在使用Spring @RequestMapping来使用和生成JSON的REST同步服务。我现在想要添加异步响应,如果客户端发送了一个id列表,服务器会将详细信息发回给它,只有那个客户端。
我一直在寻找并找不到我要找的东西。我见过两种不同的Spring方法。最常见的是消息代理方法,似乎每个人都通过订阅队列或主题来获取每条消息。这是非常不可接受的,因为这是私人数据。我还有一定数量的数据点可以返回。另一种方法是Callable,AsyncResult或DeferredResult。这似乎保持数据私密,但我想发送多个回复。
我已经看到类似于我想要的东西,但在服务器上使用Jersey SSE。我想坚持使用Spring。
这是我目前使用的伪代码。
@RequestMapping(value = BASE_PATH + "/balances", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public GetAccountBalancesResponse getAccountBalances(@RequestBody GetAccountBalancesRequest request) {
GetAccountBalancesResponse ret = new GetAccountBalancesResponse();
ret.setBalances(synchronousService.getBalances(request.getIds());
return ret;
}
这就是我要做的。这是相当粗糙的,因为我不知道细节。一旦我发现发送,我将处理异步部分,但会采取任何建议。
@RequestMapping(value = BASE_PATH + "/balances", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ???<BalanceDetails> getAccountBalances(@RequestBody GetAccountBalancesRequest request) {
final ???<BalanceDetails> ret = new ???<>();
new Thread(new Runnable() {
public void run() {
List<Future<BalanceDetails>> futures = asynchronousService.getBalances(request.getIds());
while(!stillWaiting(futures)) {
// Probably use something like a Condition to block until there is some details.
ret.send(getFinishedDetails(futures));
}
ret.close();
}
}).start();
return ret;
}
谢谢,Wes。
答案 0 :(得分:0)
它不会像这样工作:您正在使用普通的Spring操作,这些操作旨在在单个线程中处理,该线程可能会阻塞,直到计算完整的请求。你不能在控制器内部创建线程 - 或者至少不是这样。
如果计算持续时间很长,并且您希望为用户提供视觉反馈,请执行以下步骤:
如果仍然不够,计算仍然会持续,用户需要反馈,您将有两个选择
答案 1 :(得分:0)
进行了大量挖掘,但看起来Spring Web 4.2确实支持服务器端事件。我使用的是使用Spring Web 4.1.7的Spring Boot 1.2.7。切换到Spring Boot 1.3.0.RC1添加了SseEmitter。
这是我的伪代码。
@RequestMapping(value = BASE_PATH + "/getAccountBalances", method = RequestMethod.GET)
public SseEmitter getAccountBalances(@QueryParam("accountId") Integer[] accountIds) {
final SseEmitter emitter = new SseEmitter();
new Thread(new Runnable() {
@Override
public void run() {
try {
for (int xx = 0; xx < ids.length; xx++) {
Thread.sleep(2000L + rand.nextInt(2000));
BalanceDetails balance = new BalanceDetails();
...
emitter.send(emitter.event().name("accountBalance").id(String.valueOf(accountIds[xx]))
.data(balance, MediaType.APPLICATION_JSON));
}
emitter.send(SseEmitter.event().name("complete").data("complete"));
emitter.complete();
} catch (Exception ee) {
ee.printStackTrace();
emitter.completeWithError(ee);
}
}
}).start();
return emitter;
}
仍在努力优雅地关闭频道并使用Jersey EventSource解析JSON对象,但它比消息总线要好得多。
同样产生一个新线程并使用睡眠仅适用于POC。我不需要,因为我们已经有一个异步进程来访问慢速后端系统。
韦斯。