如果我忘记将Spring SessionStatus标记为“完成”会怎样?

时间:2009-05-19 02:37:02

标签: spring session spring-mvc annotations

在Spring MVC中,假设我使用@SessionAttribute标记来定义SessionAttribute,如下所示:

@SessionAttributes(value = "myModel")
public class MyController{
   ...
}

假设我忘记在SessionStatus上调用status.setComplete(),如下所示:

@RequestMapping(method = RequestMethod.POST)
public void doSomething(@ModelAttribute("myModel") MyModel model, SessionStatus status){
   ...
   //status.setComplete(); <-- Never gets called
}

模特会永远留在会话中吗?它是否会被清除,或者当用户浏览网站时会话会不断变大和变大?

3 个答案:

答案 0 :(得分:22)

关于在控制器退出后是否清除会话属性存在很大争议。

为了澄清一下,我们可以看一下 Spring MVC 3.1.0 RELEASE 源代码。

界面 org.springframework.web.bind.support.SessionAttributeStore 公开以下方法:

void storeAttribute(WebRequest request, String attributeName, Object attributeValue);

Object retrieveAttribute(WebRequest request, String attributeName);

void cleanupAttribute(WebRequest request, String attributeName);

默认实施是 org.springframework.web.bind.support.DefaultSessionAttributeStore

通过在Eclipse中的 cleanupAttribute()上执行“ Open Call Hierarchy ”,我们可以看到该方法由2个不同的流调用:

1) org.springframework.web.method.annotation.ModelFactory

public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {

        if (mavContainer.getSessionStatus().isComplete()){
            this.sessionAttributesHandler.cleanupAttributes(request);
        }
        else {
            this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
        }

        if (!mavContainer.isRequestHandled()) {
            updateBindingResult(request, mavContainer.getModel());
        } 
    }

2) org.springframework.web.bind.annotation.support.HandlerMethodInvoker

public final void updateModelAttributes(Object handler, Map<String, Object> mavModel,
            ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception {

        if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) {
            for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
                this.sessionAttributeStore.cleanupAttribute(webRequest, attrName);
            }
        }
...
}

很明显,在这两种情况下,只有在调用 this.sessionStatus.isComplete()时才会删除会话属性。

我挖掘了 DefaultSessionAttributeStore 的代码。在引擎盖下,它获得了真正的 HTTP Session 对象来存储属性,因此它们可能被同一会话中的其他控制器访问。

所以不,在干净的POST后不会删除会话属性。

答案 1 :(得分:12)

编辑#2:请注意,这个答案不再正确。请参阅下面的@doanduyhai's answer

编辑:请注意,这是针对Spring 2.5并且可能,但不一定确保Spring 3.x也是如此。仔细检查文档!

这与@Gandalf所说的一致。

表单控制器为表单请求生命周期建模,从最初查看表单到表单提交。提交表单后,表单控制器的作业完成,它将从会话中删除命令对象。

因此,要将命令对象保留在表单工作流之间的会话中,您需要手动管理会话。在干净的POST之后,该对象将从会话中删除。

简而言之,我相信setComplete()方法只是一种很好的做法,但不一定是必需的。

编辑:我刚看了我的春季书就证实了这一点。我会引用它:

  

当未使用@SessionAttribute时,a   将创建新的命令对象   每个请求,即使在渲染时也是如此   由于绑定错误再次形成。如果   这个注释已启用,   命令对象将存储在   后续用途的会话,直到   表单成功完成。然后   此命令对象将被清除   来自会议。这通常是   当命令对象是a时使用   需要的持久对象   不同的请求相同   跟踪变化。

基本上就是我上面所说的。它将它存储在会话中,直到您A)调用setComplete()或B)控制器成功完成POST。

答案 2 :(得分:1)

你有什么理由要这么做吗?

来自这个帖子:@SessionAttribute Problem

  

@SessionAttributes的工作方式与SimpleFormController的sessionForm相同。它将命令(或@SessionAttributes任何对象)放在会话中,持续时间为第一个和最后一个请求(大多数时间是初始GET和最终POST)。之后,这些东西被删除了。