JSF什么时候创建会话
确定这一点的最简单方法是创建一个HttpSessionListener,放置调试断点sessionCreated()
方法并检查第一次需要获取会话的调用堆栈(因此隐式需要创建它)。
在下面的示例中,您将看到一串getSession()
调用堆栈中的调用。你会看到FaceletViewHandlingStrategy.renderView()
方法是第一次调用它的方法。
点击后FaceletViewHandlingStrategy.renderView()
调试器调用堆栈中的行,您将进入其源代码(Maven 将自动加载源代码,否则您需要手动附加它)。
您会看到,当启用服务器端状态保存并且要渲染的视图不是瞬态的(无国籍的),然后 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
分别。
事实上,我正在使用@Named @ViewScoped
它由特定页面上的值表达式引用(您可以在调用堆栈中进一步看到 EL 解析器和 Weld 解析器)。当您点击ViewScopeContextManager.getContextMap()
在调用堆栈中的行中,您会看到它只是在会话范围内准备一个映射,以便存储视图范围的 bean。
这只是一个例子。会话中可以存储更多内容。以这种方式使用调试器并检查相关的源代码将告诉我们很多关于Why.