Let's say I specify an outputText component like this:
<h:outputText value="#{ManagedBean.someProperty}"/>
If I print a log message when the getter for someProperty
is called and load the page, it is trivial to notice that the getter is being called more than once per request (twice or three times is what happened in my case):
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
If the value of someProperty
is expensive to calculate, this can potentially be a problem.
I googled a bit and figured this is a known issue. One workaround was to include a check and see if it had already been calculated:
private String someProperty;
public String getSomeProperty() {
if (this.someProperty == null) {
this.someProperty = this.calculatePropertyValue();
}
return this.someProperty;
}
The main problem with this is that you get loads of boilerplate code, not to mention private variables that you might not need.
What are the alternatives to this approach? Is there a way to achieve this without so much unnecessary code? Is there a way to stop JSF from behaving in this way?
Thanks for your input!
With JSF 2.0 you can attach a listener to a system event
Alternatively you can enclose the JSF page in an
f:view
tagOriginally posted in PrimeFaces forum @ http://forum.primefaces.org/viewtopic.php?f=3&t=29546
Recently, I have been obsessed evaluating the performance of my app, tuning JPA queries, replacing dynamic SQL queries with named queries, and just this morning, I recognized that a getter method was more of a HOT SPOT in Java Visual VM than the rest of my code (or majority of my code).
Getter method:
Referenced by ui:include in in index.xhtml
Below, you will see that PageNavigationController.getGmapsAutoComplete() is a HOT SPOT (performance issue) in Java Visual VM. If you look further down, on the screen capture, you will see that getLazyModel(), PrimeFaces lazy datatable getter method, is a hot spot too, only when enduser is doing a lot of 'lazy datatable' type of stuff/operations/tasks in the app. :)
See (original) code below.
Referenced by the following in index.xhtml:
Solution: since this is a 'getter' method, move code and assign value to gmapsAutoComplete prior to method being called; see code below.
Test results: PageNavigationController.getGmapsAutoComplete() is no longer a HOT SPOT in Java Visual VM (doesn't even show up anymore)
Sharing this topic, since many of the expert users have advised junior JSF developers to NOT add code in 'getter' methods. :)
This is caused by the nature of deferred expressions
#{}
(note that "legacy" standard expressions${}
behave exactly the same when Facelets is used instead of JSP). The deferred expression is not immediately evaluated, but created as aValueExpression
object and the getter method behind the expression is executed everytime when the code callsValueExpression#getValue()
.This will normally be invoked one or two times per JSF request-response cycle, depending on whether the component is an input or output component (learn it here). However, this count can get up (much) higher when used in iterating JSF components (such as
<h:dataTable>
and<ui:repeat>
), or here and there in a boolean expression like therendered
attribute. JSF (specifically, EL) won't cache the evaluated result of the EL expression at all as it may return different values on each call (for example, when it's dependent on the currently iterated datatable row).Evaluating an EL expression and invoking a getter method is a very cheap operation, so you should generally not worry about this at all. However, the story changes when you're performing expensive DB/business logic in the getter method for some reason. This would be re-executed everytime!
Getter methods in JSF backing beans should be designed that way that they solely return the already-prepared property and nothing more, exactly as per the Javabeans specification. They should not do any expensive DB/business logic at all. For that the bean's
@PostConstruct
and/or (action)listener methods should be used. They are executed only once at some point of request-based JSF lifecycle and that's exactly what you want.Here is a summary of all different right ways to preset/load a property.
Note that you should not use bean's constructor or initialization block for the job because it may be invoked multiple times if you're using a bean management framework which uses proxies, such as CDI.
If there are for you really no other ways, due to some restrictive design requirements, then you should introduce lazy loading inside the getter method. I.e. if the property is
null
, then load and assign it to the property, else return it.This way the expensive DB/business logic won't unnecessarily be executed on every single getter call.
See also:
You could probably use AOP to create some sort of Aspect that cached the results of our getters for a configurable amount of time. This would prevent you from needing to copy-and-paste boilerplate code in dozens of accessors.
I have written an article about how to cache JSF beans getter with Spring AOP.
I create a simple
MethodInterceptor
which intercepts all methods annotated with a special annotation:This interceptor is used in a spring configuration file:
Hope it will help!
This is what we call a premature optimization. In the rare case that a profiler tells you that the calculation of a property is so extraordinarily expensive that calling it three times rather than once has a significant performance impact, you add caching as you describe. But unless you do something really stupid like factoring primes or accessing a databse in a getter, your code most likely has a dozen worse inefficiencies in places you've never thought about.