1

我有以下 Spring MVC 3.2 代码(它使用DeferredResult 类):

@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 崩溃时没有任何错误消息。

如果有人可以帮助我确定此代码表现出这种行为的原因,我将非常感激,或许可以通过给我有关如何调试应用程序/tomcat 的提示。

4

1 回答 1

1

我试过你修改过的mvc-chat 代码

有了它,我一登录就发出了一个 GET 请求,由于超时为 3 秒,它超时并且 GET 响应带有一个空的消息列表。客户端立即发出另一个 GET 请求作为响应,第二个 GET 挂在“myService.someTransactionalMethod();”中 在对“messageRepository.findAll();”的调用中 !

如果我增加超时并让 GET 请求“完成”,那么后续的 GET 请求能够正确调用启用 Tx 的方法。但是,如果请求“超时”,则后续 GET 请求(来自同一聊天客户端)在启用 Tx 的方法中被阻止。(即清理问题)。

同样,当 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 实例。

于 2013-04-25T22:48:13.653 回答