在每个ajax请求上重新构建JSF视图



我有一个性能问题与我的JSF/RichFaces/Facelets ajax请求,从我可以告诉它,因为整个组件树正在重建每个ajax请求。即使我使用ajaxSingle=true,在a4j:region中包装部分,声明一个部分用于重新渲染或根本没有,也会发生这种情况。我们的页面是一个具有许多嵌套级别的动态页面。该页面可能包含大约800-900个字段(inputText、富日历、selectOneMenus等)。初始加载时间是一个问题,但我理解这个问题,它的很多领域。一旦我们有了最初的构建/渲染时间,尽管我们已经将所有其他动作设计为ajax,并且只渲染所需的内容。从facelets调试日志中,我看到任何ajax调用都有这样的消息:

2011-08-24 22:19:03,054 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took
24445ms to build view: /oconsole/appfile.xhtml
2011-08-24 22:19:09,377 DEBUG [facelets.viewhandler] (http-0.0.0.0-8080-2) Took
6323ms to render view: /oconsole/appfile.xhtml

我不确定我们正在做的事情是否会导致整个组件树的重建,或者facelets正在确定出于某种原因(过时的缓存?)所需的这种需求。下面是我们的堆栈:JBoss 5.1JSF 1.2RichFaces。3.3.3.FinalFacelets 1.1.15Seam 2.1.2

我试着添加一些上下文参数,看看他们是否有帮助,但他们什么也没做:facelets。BUILD_BEFORE_RESTORE = falsefacelets。REFRESH_PERIOD = -1或5(如5min)

是否有办法告诉我们的视图是否被正确缓存?我们没有声明状态保存方法,所以我认为它默认为服务器端。我们所有的请求都发生在长时间运行的会话中。我不确定这是否起到了一个因素,因为我认为视图在会话级别得到缓存?如有任何帮助,我将不胜感激,谢谢。

调试后更新:

AjaxViewHandler(它有一个FaceletsViewHandler的成员变量)有developmentMode=true设置。我不确定这是否会导致facelets不缓存任何视图,以便在开发周期中刷新任何更改…??很难找到任何关于facelets/JSF缓存视图、行为和控制的信息。此外,当我添加配置参数:

<context-param>
<param-name>facelets.DEVELOPMENT</param-name>
<param-value>false</param-value>
</context-param>

这没有采取!在调试器中,我仍然看到true set。因为我们有很多子视图,我也试过com.sun.faces.numberOfLogicalViews和com.sun.faces.numberOfViewsInSession从15(默认值)提高到1000,这没有影响。

我也尝试改变客户端状态保存没有任何运气。没主意了....希望有人能帮忙....

似乎Seam 2.1自动初始化RichFaces,我不确定这是否与它有关.....

对于任何性能问题,性能分析器将极大地帮助定位瓶颈。(是的,您知道这是restore_view阶段,但不知道在restore_view阶段的哪个位置)。

也就是说,恢复视图阶段确实恢复了整个视图,而不仅仅是将要处理或呈现的部分。引用RichFaces标签库文档:

process: Id['s](在调用uiccomponent . findcomponent()的格式)的组件,在阶段2-5处理的情况下,由该组件引起的AjaxRequest。可以是单个id,逗号分隔的id列表,或带有数组或集合的EL表达式

RESTORE_VIEW是阶段1。还:

renderer: Id['s] (in format of call uiccomponent . findcomponent ()) of components,在由该组件引起的AjaxRequest情况下呈现。可以是单个id,逗号分隔的id列表,或带有数组或集合的EL表达式

此外,我不确定uiccomponent . findcomponent()是使用比组件树更合适的数据结构实现的。(在组件树中寻找某些东西将归结为线性搜索…)。

我在JSF 2.0 (Mojarra)中观察到了类似的效果。我的结论是视图不能包含超过几十个ui组件,不管它们是否被渲染。(换句话说,AJAX不适合页面导航。)我们倾向于通过只包含当前在视图中可见的组件来保持视图的小,并且在需要出现许多新组件时切换视图。也就是说,不是一个视图有10个选项卡,每个选项卡有30个组件,而是有10个视图,每个视图只包含一个选项卡的内容。这种方法的一个缺点是,组件在切换选项卡时被丢弃,导致任何未保存在支持bean中的状态丢失。

我不认为这是一个好的解决方案。唉,这是我在几周前调查这个问题时发现的最好的一个。如果能给我一个更好的,我也会很高兴的。

编辑当我说还原时,我指的是ViewHandler.restoreView(),它同时调用初始get请求和回发请求。说restoreView只是按原样重用现有视图是不正确的。例如,JSF 2.0规范在第7.6.2.7节中规定:]

restoreView()方法必须完成以下职责:

所有实现必须:

  • 如果没有viewId,返回null
  • 调用关联StateManagerrestoreView()方法,传递FacesContext实例返回当前请求和计算的viewId,并返回返回的UIViewRoot,也可能是null

和第7.7.2节中的

的值为基础,JSF实现支持两种保存状态的主要机制javax.faces。STATE_SAVING_METHOD初始化参数(参见11.1.3节"应用配置")参数")。此参数的可能值给出了要使用的方法的一般指示,同时允许在技术细节上进行创新的JSF实现:
  • 客户端—[…]
  • server——在请求之间将保存的状态存储在服务器上。希望启用的实现在实现它们的服务器时,必须记住它们保存的状态以故障转移到不同的容器实例侧状态保存策略。默认实现以客户机和服务器两种模式序列化视图。在服务器模式下,这个序列化的视图存储在会话中,检索视图的唯一键被发送到客户端。通过在会话中存储序列化视图,可以使用类提供的常用机制进行故障转移容器。

换句话说,添加到JSF中的AJAX支持(包括由RichFaces 3添加到JSF 1.2中的AJAX支持和合并到JSF 2.0中的AJAX支持)旨在减少网络带宽消耗,而不是服务器端cpu消耗。

根据我的分析,这个问题是由facelets的实现引起的。基于调试器FaceletViewHandler类的以下行,导致每个(甚至AJAX)请求重新构建树(buildBeforeRestore为false,因此调用buildView方法):

        // build view - but not if we're in "buildBeforeRestore"
        // land and we've already got a populated view. Note
        // that this optimizations breaks if there's a "c:if" in
        // the page that toggles as a result of request processing -
        // should that be handled? Or
        // is this optimization simply so minor that it should just
        // be trimmed altogether?
        if (!this.buildBeforeRestore
                || viewToRender.getChildren().isEmpty()) {
            this.buildView(context, viewToRender);
        }

所以在我看来,解决每个请求的树重建问题是深入到facelets实现并重新实现…我更倾向于重构视图并最小化组件的数量,这样构建树的时间就很低。

相关内容

  • 没有找到相关文章

最新更新