我有以下Spring MVC 3.2代码(它使用DeferredResult class):
@RequestMapping(value = "getMessages", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public DeferredResult<List<Message>> getMessages(@RequestParam final Long senderId) {
final Long recipientId = memberService.retrieveCurrentMember().getId();
final String messageRequestKey = new StringBuilder().append(senderId).append(":").append(recipientId).toString();
final DeferredResult<List<Message>> deferredResult = new DeferredResult<List<Message>>(null, Collections.emptyList());
messageRequests.put(messageRequestKey, deferredResult);
deferredResult.onCompletion(new Runnable() {
@Override
public void run() {
messageRequests.remove(messageRequestKey);
}
});
List<Message> unReadMessages = messageService.findUnreadMessages(senderId, recipientId);
if (!unReadMessages.isEmpty()) {
deferredResult.setResult(unReadMessages);
}
return deferredResult;
}
通过ajax调用连续轮询此方法,系统地导致Tomcat在第9个方法调用时崩溃。请注意,Tomcat崩溃时没有任何错误消息。
如果有人可以帮助我确定此代码表现出此行为的原因,或许可以通过向我提供有关如何调试app / tomcat的提示,我将非常感激。
答案 0 :(得分:1)
我尝试了修改后的mvc-chat code。
有了它,我登录时就发出了一个GET请求,因为超时是3秒,它是timedout,GET响应带有一个空的消息列表。客户端立即发出另一个GET请求以响应这个,第二个GET挂在“myService.someTransactionalMethod();”中在调用“messageRepository.findAll();” !
如果我增加超时并让GET请求“完成”,则后续GET请求可以正确调用启用Tx的方法。 但是,如果请求'timedout',则在启用Tx的方法中阻止后续GET请求(来自同一聊天客户端)。 (即清理问题)。
类似地,当GET未完成且发出并行GET时(例如,从另一个浏览器窗口发出),第二个GET在启用Tx的方法中被阻止。
这似乎是DeferredResult与OEMIV过滤器语义交互的问题。 你在Spring论坛中提出这个做了正确的事情!
Edit1:为了确认上述声明,我从xml中移除了OEMIV过滤器(并保留了所有其他代码,包括Tx方法和DeferredResult,未更改),并且它没有任何问题。
Edit2:Rossen Stoyanchev在Spring论坛上评论说:
"On the initial request thread, the OEMIV filter acquires an EM instance, then the
controller is invoked, which in turn invokes the tx method. The tx method re-uses the
same EM instance. Then the controller method returns and the Servlet container thread
is exited, but OEMIV filter doesn't release the EM instance because it is aware of the
async processing.
When the DeferredResult is set, a dispatch is made back to the container, hitting the
OEMIV filter and the DispatcherServlet once again. When that thread completes, OEMIV
filter will release the EM instance. Note that this is true even if the DeferredResult
is set in the controller method.".
从上面可以看出,当异步请求超时时,OEMIV过滤器要么没有参与,即使它确实涉及它,也没有机会释放它所持有的EM实例。 / p>