如何在单个浏览器标签页中维护多个JSF视图根以优化性能?
嘿,这个问题我在不少JSF项目里都碰到过——用jQuery做多标签页把一堆xhtml塞到同一个ViewRoot里,开的标签越多,视图恢复阶段越慢,确实挺头疼的。给你几个实用的解决方案,都是经过项目验证的:
1. 拆分ViewRoot,给每个标签页独立的视图上下文
JSF视图恢复阶段的核心开销就是遍历整个ViewRoot的组件树,组件越多,遍历和状态恢复的耗时就呈线性增长。最彻底的解决办法就是让每个标签页拥有自己的独立ViewRoot:
- 最简单的实现方式是用
<iframe>承载每个标签页的内容,每个iframe对应一个独立的JSF请求和视图,天然隔离了组件树,完全避免单棵树过大的问题。 - 如果不想用iframe,也可以基于JSF的
ViewHandlerAPI动态创建和管理多个ViewRoot,不过这种方式需要自己处理视图切换的逻辑,复杂度高一些。 - 注意:如果需要标签页间通信,可以用
window.postMessage做前端通信,或者通过后端会话(比如HttpSession)传递共享数据,别直接跨视图操作组件。
2. 延迟加载+关闭时销毁组件
没必要一开始就把所有标签页的组件都加载到ViewRoot里,只在用户激活标签页时才加载对应的xhtml,关闭标签页时彻底把组件从ViewRoot中移除:
- 点击菜单项时,先判断该标签页是否已加载:未加载的话,用jQuery动态加载xhtml内容并渲染到标签页容器,同时记录该标签页对应的JSF组件引用。
- 关闭标签页时,调用
UIComponent#removeFromParent()方法把该标签页的组件树从ViewRoot中移除,释放资源。 - 如果用PrimeFaces这类组件库的话,直接用
p:tabView的dynamic="true"属性,它原生支持延迟加载标签内容,关闭标签时会自动清理对应的组件,省得自己写代码。
3. 优化JSF状态保存配置
调整JSF的核心配置,减少视图恢复阶段的工作量:
- 确保
web.xml里javax.faces.PARTIAL_STATE_SAVING设为true(默认就是true,但最好确认一下),这个配置会让JSF只保存组件的变化状态,而不是整个视图的全量状态,能大幅减少恢复时的处理量。 - 把
javax.faces.STATE_SAVING_METHOD设为server,相比client端保存状态,服务器端保存更高效,尤其是组件数量多的时候,避免了大量状态数据在前后端传输的开销。 - 对于不需要保存状态的组件(比如纯展示的静态内容),给它们加上
transient="true"属性,JSF会跳过这些组件的状态保存和恢复,进一步减少耗时。
4. 用复合组件/模板复用减少冗余组件
如果多个标签页有重复的组件结构(比如相同的工具栏、布局容器),别重复写代码,用复合组件或模板封装起来:
- 把重复的部分封装成JSF复合组件(
<cc:interface>+<cc:implementation>),每个标签页只需要引用这个复合组件,而不是重复声明一堆相同的组件,能有效减少ViewRoot里的组件总数。 - 也可以用
ui:decorate或ui:composition做模板复用,统一管理页面布局,避免冗余组件的创建。
这些方案可以单独用,也可以结合起来。比如如果标签页之间独立性强,用iframe拆分ViewRoot是最省心的;如果需要保持页面内的组件通信,延迟加载加组件销毁会更合适。
内容的提问来源于stack exchange,提问作者Raj Kumar
相关产品推荐
相关产品推荐

