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

Dan*_*iuc 17 session spring annotations spring-mvc

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

@SessionAttributes(value = "myModel")
public class MyController{
   ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

doa*_*hai 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);
Run Code Online (Sandbox Code Playgroud)

默认实现是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());
        } 
    }
Run Code Online (Sandbox Code Playgroud)

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);
            }
        }
...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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


Ale*_*ley 12

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

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

这与@Gandalf所说的一致.

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

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

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

编辑:我只是看了我的春季书来证实这一点.我引用它:

如果未使用@SessionAttribute,则会在每个请求上创建一个新的命令对象,即使在由于绑定错误而再次呈现表单时也是如此.如果启用此批注,则命令对象将存储在会话中以供后续使用,直到窗体成功完成.然后将从会话中清除此命令对象. 这通常在命令对象是持久对象时使用,该对象在跟踪更改的不同请求之间需要相同.

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