为什么 JSF 需要在服务器端保存 UI 组件的状态?
因为HTTP是无状态的,而JSF是有状态的。JSF 组件树受动态(编程)更改的影响。JSF 只需要知道表单显示给最终用户时的确切状态,以便它可以根据表单提交回服务器时原始 JSF 组件树提供的信息成功处理整个 JSF 生命周期。组件树提供有关请求参数名称、必要的转换器/验证程序、绑定的受管 Bean 属性和操作方法的信息。
JSF 在什么时间点保存服务器端 UI 组件的状态,以及从服务器内存中删除 UI 组件的状态信息究竟是什么时候?
这两个问题似乎归结为同一点。无论如何,这是特定于实现的,并且还取决于状态是保存在服务器还是客户端上。一个稍微体面的实现将在它过期或队列已满时将其删除。例如,当状态保存设置为会话时,Mojarra 的默认限制为 15 个逻辑视图。这可以使用以下上下文参数进行配置:web.xml
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>15</param-value>
</context-param>
另请参阅 Mojarra FAQ 了解其他特定于 Mojarra 的参数,以及此相关答案 com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews
当应用程序上的登录用户在页面中导航时,组件的状态是否会继续在服务器上累积?
从技术上讲,这取决于实现。如果您正在谈论页面到页面导航(只是GET请求),那么Mojarra不会在会话中保存任何内容。但是,如果它们是POST请求(带有命令链接/按钮的表单),则Mojarra将在会话中保存每个表单的状态,直到达到最大限制。这使最终用户能够在同一会话中的不同浏览器选项卡中打开多个表单。
或者,当状态保存设置为客户端时,JSF 将不会在会话中存储任何内容。您可以通过以下上下文中的上下文参数来执行此操作:web.xml
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
然后,它将被序列化为具有表单名称的隐藏输入字段中的加密字符串。javax.faces.ViewState
我不明白在服务器端保留UI组件状态的好处是什么。直接将验证/转换的数据传递给托管 Bean 还不够吗?我可以/应该尝试避免它吗?
这还不足以确保 JSF 的完整性和稳健性。JSF 是一个具有单一入口控制点的动态框架。如果没有状态管理,人们将能够以某种方式欺骗/破解HTTP请求(例如操纵和属性),让JSF做不同且潜在危险的事情。它甚至容易受到CSRF攻击和网络钓鱼。disabled
readonly
rendered
如果有数千个并发用户会话,这不会在服务器端消耗太多内存吗?我有一个应用程序,用户可以在其中发布有关某些主题的博客。这个博客的规模相当大。当有回发或请求查看博客时,大型博客将保存为组件状态的一部分。这将消耗太多内存。这不是一个问题吗?
内存特别便宜。只需为应用程序服务器提供足够的内存即可。或者,如果网络带宽对您来说更便宜,只需将状态保存切换到客户端即可。要找到最佳匹配项,只需对 Web 应用进行压力测试,并使用预期的最大并发用户数分析 Web 应用,然后为应用服务器提供最大测量内存的 125% ~ 150%。
请注意,JSF 2.0 在状态管理方面有了很大的改进。可以保存部分状态(例如,仅保存将保存,而不是从一直到最后的整个内容)。例如,Mojarra就是这样做的。具有 10 个输入字段(每个字段都有一个标签和消息)和 2 个按钮的平均表单将不超过 1KB。如果会话中有 15 个视图,则每个会话不应超过 15KB。对于大约 1000 个并发用户会话,这不应超过 15MB。<h:form>
<html>
您的关注点应更多地关注会话或应用程序范围内的真实对象(托管 Bean 和/甚至 DB 实体)。我见过很多代码和项目,它们不必要地将整个数据库表复制到Java的内存中,就像会话范围的bean一样,其中使用Java而不是SQL来过滤/分组/排列记录。对于大约 1000 条记录,每个用户会话可以轻松超过 10MB。