0

这是可以重现此问题的代码:

@Controller
public class FirstController {
    @RequestMapping(value = "firstpage", method = GET)
    public String myHander(HttpSession httpSession) {
        if (httpSession.getAttribute("someClass") == null) {
            httpSession.setAttribute("someClass", new SomeClass());
        }
        return "firstpage";
    }
}

如果会话中不存在,第一个控制器会将其放入会话中。

@Controller
@SessionAttributes(types = SomeClass.class)
public class SecondController {

    @RequestMapping(value = "secondpage", method = GET)
    public String myHandler(SomeClass someClass, HttpSession httpSession) {
        //asking spring for the SomeClass parameter, that's why we put it in the annotation.
        System.out.print(someClass.hashCode());

        httpSession.invalidate();

        return "secondpage";
    }
}

第二个控制器终止会话。

在两个 jsp 文件中,我都有以下代码打印会话对象的哈希码和会话属性的哈希码:

session hash:
<%= session.hashCode() %>
<br/>
someclass hash:
<%= session.getAttribute("someClass").hashCode() %>

现在如果我运行应用程序并访问“首页”,我会得到这个:

会话哈希:1838367636

某类哈希:1075505853

然后我访问“第二页”,会得到这个:

会话哈希:842656294

某类哈希:1075505853

我们可以看到会话本身发生了变化,因为第二个控制器终止了会话。但会话属性(SomeClass 类型)保持不变。

然后,如果我尝试重新访问“第二页”,会话对象每次都会更改,但会话属性保持不变。

为什么会话属性(应该附加到会话)的生命周期比会话本身更长?

PS:完整代码在这里:https ://github.com/cuipengfei/One-hundred-thousand-why/tree/master/20130701SessionAttributesLifeCycle/SpringMVC

您可以使用 mvn jetty:run 运行它来重现问题。

4

1 回答 1

1

该注释的文档不是特别清楚,但我的理解是它用于在同一控制器中的方法之间共享值。当我阅读以下内容时:

这通常会列出模型属性的名称或模型属性的类型,它们应该透明地存储在会话或某些会话存储中,作为后续请求之间的表单支持 bean

我将其解释为意味着每个控制器方法调用都将包含一个调用(1)在进入之前加载会话属性,以及(2)在退出时存储它们。这将具有您所看到的行为。

注释的 javadoc 中的以下内容加强了这一点(imo):

对于永久会话属性,例如用户身份验证对象,请改用传统的 session.setAttribute 方法

如果他们告诉您使用标准函数来修改会话,这向我表明注释不仅仅是访问会话中项目的一种方式。

最后一个数据点:如果这个注解管理会话数据的方式,为什么有会话范围的 bean?

于 2013-07-01T15:07:08.777 回答