简体   繁体   English

JSF视图在每个ajax请求上进行重建

[英]JSF view getting rebuild on each ajax request

I'm having a performance problem with my JSF/RichFaces/Facelets ajax requests and from what I can tell its because the entire component tree is being rebuild on each ajax request. 我的JSF / RichFaces / Facelets ajax请求存在性能问题,而且我可以告诉它,因为整个组件树正在每个ajax请求上重建。 This is happening even if I use ajaxSingle=true, wrap sections in a4j:region, declare a single section for rerendering or none at all. 即使我使用ajaxSingle = true,在a4j:区域中包装部分,声明单个部分进行重新渲染或根本不进行渲染,也会发生这种情况。 Our page is a dynamic page with many nested levels. 我们的页面是一个包含许多嵌套级别的动态页面。 The page may contain around 800-900 fields (inputText, rich calendars, selectOneMenus, etc). 该页面可能包含大约800-900个字段(inputText,富日历,selectOneMenus等)。 The initial load time is an issue, but I understand that issue, its a lot of fields. 初始加载时间是一个问题,但我理解这个问题,它有很多领域。 Once we have that initial build/render time though we have designed all other actions to be ajax and only reRender what is needed. 一旦我们有了初始构建/渲染时间,虽然我们已经将所有其他操作设计为ajax并且只需要reRender。 From facelets debug logs I see messages like this on any ajax call: 从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

I'm not sure if something we are doing is causing the rebuild of the entire component tree, or facelets is determining this need required for some reason (stale cache?). 我不确定我们正在做的事情是否导致整个组件树的重建,或者facelets是否正在确定由于某种原因(过时的缓存?)所需的这种需求。 Here is our stack: JBoss 5.1 JSF 1.2 RichFaces. 这是我们的堆栈:JBoss 5.1 JSF 1.2 RichFaces。 3.3.3.Final Facelets 1.1.15 Seam 2.1.2 3.3.3.Final Facelets 1.1.15 Seam 2.1.2

I have tried adding some context parameters to see if they would help, but they did nothing: facelets.BUILD_BEFORE_RESTORE = false facelets.REFRESH_PERIOD = -1 or 5 (as in 5min) 我尝试添加一些上下文参数来查看它们是否有用,但它们什么也没做:facelets.BUILD_BEFORE_RESTORE = false facelets.REFRESH_PERIOD = -1或5(如5分钟)

Is there anyway to tell if our views are being cached properly? 无论如何要告诉我们的观点是否正确缓存? We do not delcare a state saving method, so I believe it defaults to server side. 我们没有delcare一个状态保存方法,所以我认为它默认为服务器端。 All our requests happen within seam long running conversations. 我们所有的请求都发生在长时间运行的对话中。 I wasn'te sure if this plays a factor as I thought views get cached at session level? 我不确定这是否会影响因为我认为视图会话缓存在会话级别? Any help would be greatly appreciated, thank you. 非常感谢任何帮助,谢谢。

Update after more debugging: 更多调试后更新:

The AjaxViewHandler (which has a member variable of the FaceletsViewHandler) has developmentMode=true set. AjaxViewHandler(具有FaceletsViewHandler的成员变量)具有developmentMode = true set。 I'm not sure if this is causing facelets to not cache any views so any changes would be refreshed during development cycles...?? 我不确定这是否会导致facelets不缓存任何视图,因此任何更改都会在开发周期中刷新...? Its been very difficult to find any information on facelets/JSF caching of views and the behavior and controlling that. 很难找到关于facelets / JSF缓存视图以及行为和控制的任何信息。 Furthermore, when I add config param: 此外,当我添加配置参数时:

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

This did not take! 这没用! In debugger I still see true set. 在调试器中,我仍然看到真正的设置。 Since we have a lot of subviews I also tried com.sun.faces.numberOfLogicalViews and com.sun.faces.numberOfViewsInSession to 1000 up from 15(default) and this had no effect. 由于我们有很多子视图,我还尝试了com.sun.faces.numberOfLogicalViews和com.sun.faces.numberOfViewsInSession从15(默认值)到1000,这没有任何效果。

I also tried changing to client side state saving without any luck. 我也试过改变客户端状态保存没有任何运气。 Running out of ideas....hope someone can help.... 耗尽了想法......希望有人可以提供帮助....

It seems Seam 2.1 auto-initializes RichFaces and I'm not sure if that has something to do with it..... 似乎Seam 2.1自动初始化了RichFaces,我不确定它是否与它有关.....

As with any performance problem, a profiler would help greatly in locating the bottlenecks. 与任何性能问题一样,分析器将有助于找到瓶颈。 (Yes, you know it is the restore_view phase, but not where in the restore_view phase). (是的,您知道它是restore_view阶段,但不是restore_view阶段的位置)。

That said, the restore view phase indeed restores the entire view, not just the parts that will be processed or rendered. 也就是说,恢复视图阶段确实恢复了整个视图,而不仅仅是要处理或渲染的部分。 Quoting the RichFaces taglib documentation : 引用RichFaces taglib文档

process: Id['s] (in format of call UIComponent.findComponent()) of components, processed at the phases 2-5 in case of AjaxRequest caused by this component. process:Id ['s](以调用UIComponent.findComponent()的格式)组件,在由此组件引起的AjaxRequest的情况下,在阶段2-5处理。 Can be single id, comma-separated list of Id's, or EL Expression with array or Collection 可以是单个id,以逗号分隔的Id列表,也可以是带有数组或集合的EL表达式

RESTORE_VIEW is phase 1. Also: RESTORE_VIEW是第1阶段。另外:

reRender: Id['s] (in format of call UIComponent.findComponent()) of components, rendered in case of AjaxRequest caused by this component. reRender:Id [的](以调用UIComponent.findComponent()的格式)组件,在由此组件引起的AjaxRequest的情况下呈现。 Can be single id, comma-separated list of Id's, or EL Expression with array or Collection 可以是单个id,以逗号分隔的Id列表,也可以是带有数组或集合的EL表达式

Moreover, I am not sure that UIComponent.findComponent() is implemented using a more suitable datastructure than a component tree. 而且,我不确定使用比组件树更合适的数据结构来实现UIComponent.findComponent()。 (Finding something in the component tree would boil down to linear search ...). (在组件树中查找某些内容将归结为线性搜索...)。

I have observed similar effects with JSF 2.0 (Mojarra). 我观察到JSF 2.0(Mojarra)的类似效果。 My conclusion was that views must not contain more than a couple dozen UIComponents, irrespective of whether they are rendered. 我的结论是,不管是否渲染,视图都不得包含超过几十个UIComponents。 (Put differently, AJAX is unsuitable for page navigation.) We indend to keep views small by including only components that are currently visible in the view, and switch views if many new components need to appear. (换句话说,AJAX不适合页面导航。)我们通过仅包含视图中当前可见的组件来缩小视图,并在需要显示许多新组件时切换视图。 That is, instead of one view with 10 tabs with 30 components each, we'd have 10 views, each only containing the content of a single tab. 也就是说,我们有10个视图,每个视图只包含一个标签的内容,而不是一个包含10个标签的视图,每个视图包含30个组件。 A drawback of that approach is that components are disposed when switching tabs, causing any state not held in backing beans to be lost. 该方法的缺点是在切换标签时布置组件,导致未保留在支持bean中的任何状态丢失。

I do not claim this to be a good solution. 我并不认为这是一个很好的解决方案。 Alas, it was the best one I found when looking into this a couple weeks ago. 唉,这是我几周前看到的最好的一个。 I'd be happy to be shown a better one, too. 我也很乐意被展示出更好的一个。

Edit When I say restore, I mean ViewHandler.restoreView() , which called both for an initial get request and a postback. 编辑当我说恢复时,我的意思是ViewHandler.restoreView() ,它同时调用初始获取请求和回发。 It is incorrect to say that restoreView would simply reuse an existing view as is. restoreView只是按原样重用现有视图是不正确的。 For instance, the JSF 2.0 spec mandates in section 7.6.2.7: ] 例如,JSF 2.0规范要求见7.6.2.7节:]

The restoreView() method must fulfill the following responsibilities: restoreView()方法必须履行以下职责:

All implementations must: 所有实现都必须:

  • If no viewId could be identified, return null . 如果无法识别viewId,则返回null
  • Call the restoreView() method of the associated StateManager , passing the FacesContext instance for the current request and the calculated viewId, and return the returned UIViewRoot , which may be null . 调用关联的StateManagerrestoreView()方法,传递当前请求和计算的viewId的FacesContext实例,并返回返回的UIViewRoot ,它可以为null

and in section 7.7.2: 在第7.7.2节中:

JSF implementations support two primary mechanisms for saving state, based on the value of the javax.faces.STATE_SAVING_METHOD initialization parameter (see Section 11.1.3 “Application Configuration Parameters”). 根据javax.faces.STATE_SAVING_METHOD初始化参数的值,JSF实现支持两种保存状态的主要机制(请参见第11.1.3节“应用程序配置参数”)。 The possible values for this parameter give a general indication of the approach to be used, while allowing JSF implementations to innovate on the technical details: 此参数的可能值给出了要使用的方法的一般指示,同时允许JSF实现在技术细节上进行创新:

  • client -- [...] 客户 - [...]
  • server -- Cause the saved state to be stored on the server in between requests. server - 使保存的状态在请求之间存储在服务器上。 Implementations that wish to enable their saved state to fail over to a different container instance must keep this in mind when implementing their server side state saving strategy. 希望使其已保存状态故障转移到不同容器实例的实现在实现其服务器端状态保存策略时必须牢记这一点。 The default implementation Serializes the view in both the client and server modes. 默认实现在客户端和服务器模式下序列化视图。 In the server mode, this serialized view is stored in the session and a unique key to retrieve the view is sent down to the client. 在服务器模式下,此序列化视图存储在会话中,并且用于检索视图的唯一键将向下发送到客户端。 By storing the serialized view in the session, failover may happen using the usual mechanisms provided by the container. 通过在会话中存储序列化视图,可以使用容器提供的常用机制进行故障转移。

Put differently, the AJAX support added to JSF (both the one added by RichFaces 3 to JSF 1.2, and the one incorporated into JSF 2.0) aims to reduce network bandwith consumption, not server side cpu consumption. 换句话说,添加到JSF的AJAX支持(RichFaces 3添加到JSF 1.2中的一个,以及JSF 2.0中包含的一个)旨在减少网络带宽消耗,而不是服务器端cpu消耗。

From my analysis the issue is caused by the implementation of facelets. 根据我的分析,问题是由facelets的实现引起的。 Based on debugger the following lines of FaceletViewHandler class, causes rebuild of tree on each (even AJAX) request ( buildBeforeRestore is false, so buildView method is invoked): 基于调试器, 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);
        }

So in my mind to resolve the issue of tree rebuild on each request is to go deeply to facelets implementation and do reimplementation... I would rather prefer restructure the view and minimize number of components, so build tree time is low. 所以在我看来,解决每个请求上树重建的问题是深入到facelets实现并重新实现...我宁愿重新构建视图并最小化组件数,因此构建树时间很短。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM