JSF ui:片段渲染性能

时间:2011-05-16 09:49:26

标签: java performance jsf components

我有一组jsf组件,这些组件是从一组excel文件静态生成的(它们由业务人员更新)。每个生成的文件代表一个业务对象,该业务对象具有稍微不同的数据,并且它们都属于同一个类。

为了动态渲染,我找到的唯一解决方案是设置一堆ui:fragment并在运行时调度到正确的组件:

                           

<!-- IMPLEMENTATION -->          
<composite:implementation> 
    <ui:fragment rendered="#{cc.attrs.type eq 'cartcred'}">
        <limites:limites-cartcred  limite="#{cc.attrs.limite}"/>
    </ui:fragment>
    <ui:fragment rendered="#{cc.attrs.type eq 'cdcp'}">
        <limites:limites-cdcp limite="#{cc.attrs.limite}"/>
    </ui:fragment>
    <ui:fragment rendered="#{cc.attrs.type eq 'cheqpredatado'}">
        <limites:limites-cheqpredatado limite="#{cc.attrs.limite}"/>
    </ui:fragment>
    <ui:fragment rendered="#{cc.attrs.type eq 'confirming'}">
        <limites:limites-confirming limite="#{cc.attrs.limite}"/>
    </ui:fragment>
   <!-- many more lines -->
   <!-- many more lines -->
   <!-- many more lines -->
    <ui:fragment rendered="#{cc.attrs.type eq 'contacorr'}">
        <limites:limites-contacorr limite="#{cc.attrs.limite}"/>
    </ui:fragment>

但我发现这种表现非常糟糕。我认为JSF只会渲染一个组件,但它似乎正在渲染所有,并在运行时“隐藏”其他组件。

有没有更有效的方法来实现我的目标?我想基于有关业务类的运行时信息呈现单个组件(很像if-then-else),但我只能确定在运行时要呈现的组件是什么。


澄清: 会发生什么是limites:limites*引用的每个组件都是一个包含许多其他组件的巨大复杂页面。在运行时,名为type' will decide what component to render. But my tests show that if I only render one component, but leave the other ui:fragments`的参数(即使知道它们不会被渲染),它将比移除组件时渲染更多更慢。

所以如果我的页面完全是这样的话:

<composite:interface>
    <composite:attribute name="type" required="true" />
    <composite:attribute name="limite" required="true" />
</composite:interface>         
<composite:implementation> 
    <ui:fragment rendered="#{cc.attrs.type eq 'cartcred'}">
        <limites:limites-cartcred  limite="#{cc.attrs.limite}"/>
    </ui:fragment>
</composite:implementation>

即使参数相同,它也会比初始版本更快地渲染很多(大约10倍)。我怀疑JSF将创建整个组件树,并且只在运行时它将决定(取决于提供的参数)它是否会相互渲染。


修改

几乎就在那里。我只需要动态地包含复合组件 。我尝试评估ELExpression,但这不起作用。我需要的是一种在组件创建中访问当前范围的方法,并使用它来生成正确的文件名:

//obviously, ELExpressions don't work here
Resource resource = application.getResourceHandler().createResource("file-#{varStatus.loop}.xhtml", "components/dynamicfaces");

2 个答案:

答案 0 :(得分:8)

是的,rendered属性在渲染时评估,而不是在构建时评估。是的,这是相对可怕的。想象一下这样一个条件花费1毫秒,评估其中十个将总共花费10倍,10毫秒。如果您在分页表中依次拥有10个组件,则webapp加载时间将延长0.1秒。关于一个眨眼更长。但是如果你没有分页和/或使用MSIE作为参考浏览器,那么它需要更长的时间。您是否在适当的浏览器中对数据进行分页并进行测试?

您可以做的最好的事情是将<ui:fragment>替换为<c:if> / <c:choose>等JSTL标记,以便在构建时评估,而不是在渲染时评估。或者,也可以在backing bean构造函数中而不是在视图中构建组件树。

答案 1 :(得分:2)

一种可能性是使用binding属性来访问容器 来自托管bean内部的组件,并从中构建组件树 java方面。这样,您可以只包含所需的组件,不需要 根本不会评估组件。

JSP:

<h:panelGroup binding="#{managedBean.panel}"/>

Managed Bean:

private UIPanel panel;

// getter and setter


// Action method, might also work in a @PostConstruct
public String showComponent() {
    if (showComponent1) {
        UIOutput component1 = new HtmlOutputText();
        component1.setValue("Hello world!");

        getPanel().getChildren().add(component1);
    }

    return "viewId";
}

我还没有将它与复合组件一起使用,this question似乎有更多的细节,并且example application关于将它与复合组件一起使用。

编辑:关于您的编辑,您还可以像这样评估托管bean中的EL表达式:

FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
ExpressionFactory exprFactory = facesContext.getApplication().getExpressionFactory();
ValueExpression expr = exprFactory.createValueExpression(elContext, "#{expr}", String.class);
String value = (String) expr.getValue(elContext);