为什么JSF需要在服务器端保存UI组件的状态?
因为 HTTP 是无状态的,而 JSF 是有状态的。 JSF 组件树会发生动态(编程)更改。 JSF 只需要知道表单显示给最终用户时的确切状态,以便在表单提交回时,它可以根据原始 JSF 组件树提供的信息成功处理整个 JSF 生命周期。服务器。组件树提供有关请求参数名称、必要的转换器/验证器、绑定的托管 bean 属性和操作方法的信息。当例如这disabled
or readonly
输入组件的属性以编程方式更改为true
并且这些信息保存在视图状态中,这对于防止请求被篡改起着重要的作用。
JSF 在服务器端保存 UI 组件的状态到什么时间点,以及 UI 组件的状态信息具体什么时候从服务器内存中删除?
这两个问题似乎归结为同一个问题。无论如何,这是特定于实现的,并且还取决于状态是保存在服务器还是客户端上。当它过期或队列已满时,一个适当的实现会将其删除。例如,当状态保存设置为会话时,Mojarra 的默认限制为 15 个逻辑视图。这可以使用以下上下文参数进行配置web.xml
:
<context-param>
<param-name> com.sun.faces.numberOfViewsInSession</param-name>
<param-value>15</param-value>
</context-param>
也可以看看莫哈拉常见问题解答 https://wikis.oracle.com/display/GlassFish/JavaServerFacesRI#JavaServerFacesRI-Whatcontextparametersareavailableandwhatdotheydo%3F对于其他 Mojarra 特定参数和此相关答案com.sun.faces.numberOfViewsInSession 与 com.sun.faces.numberOfLogicalViews https://stackoverflow.com/questions/4105439/jsf-numberofviewsinsession-vs-numberoflogicalviews-and-viewexpiredexception/16050424#16050424
当应用程序上的登录用户浏览页面时,组件的状态是否会继续在服务器上累积?
从技术上讲,这取决于实施。如果您谈论的是页面到页面导航(仅 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 请求(例如,操纵disabled
, readonly
and rendered
属性),让 JSF 做不同的并且有潜在危险的事情。它甚至容易受到 CSRF 攻击和网络钓鱼。
如果有数千个并发用户会话,这不会在服务器端消耗太多内存吗?我有一个应用程序,用户可以在其中发布有关某些主题的博客。这个博客的规模相当大。当有回发或请求查看博客时,大型博客将被保存为组件状态的一部分。这会消耗太多内存。这难道不是一个问题吗?
内存特别便宜。只需给应用程序服务器足够的内存即可。或者,如果网络带宽对您来说更便宜,只需将状态保存切换到客户端即可。要找到最佳匹配,只需对您的 Web 应用程序进行压力测试并使用预期的最大并发用户数进行分析,然后为应用程序服务器提供最大测量内存的 125% ~ 150%。
请注意,JSF 2.0 在状态管理方面有了很大改进。可以保存部分状态(例如only the <h:form>
将被保存而不是全部内容<html>
一直到最后)。例如,Mojarra 就是这么做的。具有 10 个输入字段(每个字段都有标签和消息)和 2 个按钮的平均表单占用的空间不超过 1KB。如果会话中有 15 个视图,则每个会话不应超过 15KB。对于大约 1000 个并发用户会话,该大小不应超过 15MB。
您应该更关注会话或应用程序范围中的真实对象(托管 bean 和/或什至数据库实体)。我见过很多代码和项目,它们不必要地将整个数据库表复制到 Java 内存中,就像会话作用域 bean 一样,其中使用 Java 而不是 SQL 来过滤/分组/排列记录。大约有 1000 条记录,很容易就会超过 10MB每个用户会话。还有当binding
用于视图或会话范围的 bean,那么您基本上就没有必要在服务器内存中保留整个 JSF 组件树的深层副本。
也可以看看:
- JSF 是否阻止通过篡改请求调用未呈现的托管 Bean 操作 https://stackoverflow.com/questions/31978113/does-jsf-prevent-calls-to-unrendered-managed-bean-actions-by-tampered-requests/
- 没有 @ViewScoped 的 JSF https://stackoverflow.com/questions/61621240/jsf-without-viewscoped/
- 视图构建时间是多少? https://stackoverflow.com/questions/31890433/whats-the-view-build-time/
- JSF 中的“绑定”属性如何工作?何时以及如何使用它? https://stackoverflow.com/questions/14911158/how-does-the-binding-attribute-work-in-jsf-when-and-how-should-it-be-used