views:

70

answers:

2

I have a JSF2 application that renders a large table with complex content. Unfortunately, each request takes up to 6 seconds to process. Using simple debug output inside a phase listener, I could see that the performance loss distributes evenly over all phases that process the component tree. So I started up a profiler to see what's going on in detail and found out that over 300.000 ValueExpressions are evaluated during one simple request.

They resolve to really simple getters without any logic, so the problem is not executing the code behind these expressions but parsing the expression string and invoking the getter methods. This leads to a few questions:

1.) Is there any way to speed up the resolving of method expressions. Maybe a hidden "enable caching" flag or something.

2.) It seems most of the expressions are evaluated not inside the render response phase, where they are actually needed, but during the other phases. It seems unnecessary to resolve for example styleClass during any other phase than the render phase. Can I prevent this?

3.) Of course, minimizing the number of EL expressions in my facelets page should help getting more performance, but it seems that I cannot really do this: Many attributes (like the styleClass example mentioned above) are actually dependent on the table row, but can only be set on the column. So, having 10 columns, each expression is evaluated much too often. I've seen examples where the rowClasses attribute of the table is used to conditionally style the rows, but as the table is sortable, that won't work without rolling my own sorting mechanism. Is there a better way to implement this?

4.) One more simple question: Is there a way to cache variables in the component tree (just like ui:repeat provides access to the contents of a list and resolves the expression to get the list only once, but just for one variable)?

Thank you very much for all answers and hints!

EDIT:

After further investigation, I found out that for each rendered=#{someExpression}, the expression is evaluated 6 times per row just during the render response phase. I know that JSF may call my getters more than once, but I thought this would be because they can be called inside each phase. During rendering, that values shouldn't change, so I guess they could be cached.

Stepping through the code in the debugger, it looks like javax.faces.component.ComponentStateHelper (which appears in each of the stack traces leading to the evaluated method call) provides a map to do exactly this kind of caching. However, this doesn't seem to work as I expect and always re-evaluates the expression...

A: 

1.) Is there any way to speed up the resolving of method expressions. Maybe a hidden "enable caching" flag or something.

No one comes to mind.

2.) It seems most of the expressions are evaluated not inside the render response phase, where they are actually needed, but during the other phases. It seems unnecessary to resolve for example styleClass during any other phase than the render phase. Can I prevent this?

This should as far as I know not happen. The only ones which could/should be resolved before render response are rendered, required, disabled, readonly and value.

3.) Of course, minimizing the number of EL expressions in my facelets page should help getting more performance, but it seems that I cannot really do this: Many attributes (like the styleClass example mentioned above) are actually dependent on the table row, but can only be set on the column. So, having 10 columns, each expression is evaluated much too often. I've seen examples where the rowClasses attribute of the table is used to conditionally style the rows, but as the table is sortable, that won't work without rolling my own sorting mechanism. Is there a better way to implement this?

You could hand over the styling work to a smart piece/combination of JS/CSS.

4.) One more simple question: Is there a way to cache variables in the component tree (just like ui:repeat provides access to the contents of a list and resolves the expression to get the list only once, but just for one variable)?

Use JSTL <c:set>. I am not sure how that would affect after all, but you're then basically only moving the problem to somewhere else. A #{variableName} would still have a cost of locating it in any of the scopes. You can also consider to name the scope explicitly when accessing the variable. E.g. #{sessionScope.beanname} which should skip unnecessarily scanning in page and request scopes.

BalusC
Does <c:set> work in tables? I thought it would only be evaluated when the component tree ist build, not for each row in the table...?
FRotthowe
+1  A: 

If you are using the mojarra reference implementation on glassfish you might try a nightly build as mentioned in this blog post by Ed Burns. There were some performance improvements contributed by the oracle adf developers relating to el expression evaluation.

Not sure if this is related, but you might also try to disable partial state saving by setting the init parameter javax.faces.PARTIAL_STATE_SAVING to false.

Jörn Horstmann
I think your answer hints to the right direction (see my edit), but unfortunately, disabling partial state saving did not help and I am using mojarra - but on Tomcat.I did some other optimizations now that limit the performance problem to only some actions which are not performed too often but I'll definitely have a look at mojarra 2.1 when it's released (or in beta).
FRotthowe