JSF 何时创建会话以及它在会话映射中放入什么内容?

2023-12-04

我正在运行 Mojarra 2.2.0。

  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>

托管 bean 操作方法是-

public void action() {
        HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
                .getExternalContext().getSession(false);
        System.out.println(session.getId()); // not null for stateful views
    }

For stateless views session.getId() throws NPE

对于非无状态的视图 - 触发 GET 请求,有JSESSIONID=340041C96D5AA446D761C3602F54A76D

我读了here that-

对于客户端状态保存机制,JSF 不会创建会话 并将视图状态存储在隐藏的输入字段中,名称为 必要时在表单中使用 javax.faces.ViewState 。

另外,这里也提到了that

JSF 确实会自动创建会话,因为 JSF 视图状态已 储存在那里。如果将 JSF 状态保存方法设置为 客户端而不是服务器,那么它不会存储在会话中,因此 无需创建会话

我认为上面的行对我来说是麻烦的根源。

如果将 JSF 状态保存方法设置为客户端而不是服务器, 那么它不会被存储在会话中 // 完全同意

and

因此不需要创建会话。 // 这令人困惑,因为 客户端保存机制,会话ID由 servlet 容器,因此有一个与 要求。

参考我与 BalusC 的讨论question, 我创建了一个 HttpSessionListener-

@WebListener
public class MyHttpSessionListener implements HttpSessionListener {

    public void sessionCreated(HttpSessionEvent event) {
        Thread.dumpStack();
    }

    public void sessionDestroyed(HttpSessionEvent event) {

    }

}

请参阅下面附加的屏幕截图(这 2 个屏幕截图适用于 2.0.3 版本,肯定存在一个旧错误导致创建会话)-

enter image description here

enter image description here

Libraby (Mojarra 2.2.0)- enter image description here


JSF什么时候创建会话

确定这一点的最简单方法是创建一个HttpSessionListener,放置调试断点sessionCreated()方法并检查第一次需要获取会话的调用堆栈(因此隐式需要创建它)。

在下面的示例中,您将看到一串getSession()调用堆栈中的调用。你会看到FaceletViewHandlingStrategy.renderView()方法是第一次调用它的方法。

enter image description here

点击后FaceletViewHandlingStrategy.renderView()调试器调用堆栈中的行,您将进入其源代码(Maven 将自动加载源代码,否则您需要手动附加它)。

enter image description here

您会看到,当启用服务器端状态保存并且要渲染的视图不是瞬态的(无国籍的),然后 JSF 将隐式创建会话,只是为了确保它按时创建以保存视图(如果会话是稍后创建的,例如在渲染响应阶段,否则您将面临这样的异常风险添加 会导致 java.lang.IllegalStateException: 提交响应后无法创建会话).

您还会在源代码中立即看到,当状态保存方法设置为客户端时,或者当视图为无状态时,如下所示<f:view transient="true">,那么 JSF 将不再隐式创建会话。较旧的 JSF 版本可能会按照您的想法执行此操作,但这将被视为错误,应该在较新的版本中修复。

如果您想确保无状态并避免意外/不可预见的会话创建,那么您可以throw new IllegalStateException() inside sessionCreated()方法。发生这种情况时,您只需查看负责创建会话的调用堆栈,然后修复/更改代码以不再这样做。


它在会话映射中放入什么?

在幕后,ExternalContext#getSessionMap()代表HttpSession#setAttribute()/getAttribute()/removeAttribute()。您可以使用以下方法监听这些方法HttpSessionAttributeListener.

在下面的例子中你会看到ViewScopeContextManager.getContextMap()线路呼叫SessionMap#put()方法以便将某些内容放入会话映射中。当你展开event参数,您将看到会话属性名称和值,即com.sun.faces.application.view.activeViewContexts和一个空的ConcurrentHashMap分别。

enter image description here

事实上,我正在使用@Named @ViewScoped它由特定页面上的值表达式引用(您可以在调用堆栈中进一步看到 EL 解析器和 Weld 解析器)。当您点击ViewScopeContextManager.getContextMap()在调用堆栈中的行中,您会看到它只是在会话范围内准备一个映射,以便存储视图范围的 bean。

enter image description here

这只是一个例子。会话中可以存储更多内容。以这种方式使用调试器并检查相关的源代码将告诉我们很多关于Why.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JSF 何时创建会话以及它在会话映射中放入什么内容? 的相关文章

随机推荐