JSF, Facelets, Myfaces and Richfaces Performance Tuning

Markus Eisele
4
I often come across the same issues in projects. One very hot topic is performance.
Beside the things you should do to garantee performance during the development process,
you are often left alone with tunings for frameworks. Good examples are the widly used JSF
frameworks Myfaces from Apache and Richfaces from JBoss.

I tried to sum up some of our performance findings during the last profiling and tuning sessions.
Happy to hear your ideas and best practices on that, too.

Myfaces General Performance Tuning

If you use the MyFacesExtensionsFilter you can start optimizing here.
It buffers and parses the response on every request.
You can disable this, and still gain all functionality the ExtensionsFilter is providing,
by doing the following.

If you use myfaces the traditional way, you end up having all resources needed for your components
beeing loaded in separate includes. You could optimize this using the following context param:

<context-param>
<param-name>org.apache.myfaces.ADD_RESOURCE_CLASS</param-name>
<param-value>org.apache.myfaces.component.html.util.StreamingAddResource</param-value>
</context-param>


The only thing to do now is get rid of the <HEAD> tag in your HTML, and instead use Tomahawk's <t:documentHead/> tag.
Of course, your <f:view/> tag has to enclose your <t:documentHead/> tag for this to work. Now
all resources needed by your components get loaded in one single file.


Think about using an optimized sirialization provider. (Following example is for JBoss)

<context-param>
<param-name>org.apache.myfaces.SERIAL_FACTORY</param-name>
<param-value>org.apache.myfaces.JbossSerialFactory</param-value>
</context-param>



Server Side State Performance Tuning

There are a many settings you can enable in your web.xml file to make MyFaces perform well.

JSF components tree state takes big enough memory. In the server-side
state saving ( default JSF behavior ) these objects are stored in the
session. For a many concurrent user connections every user gets own
session object.

In general serverside state saving is more performant than the client side. You also get lower
page sizes and faster loading times with this.

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>

If your performance is ok, but you have memory problems try to switch to the client-side state saving.

<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>

If this is not enough, you could disable serverside state compression. Compression always
takes time. If you have enought memory, try this one:

<context-param>
<param-name>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</param-name>
<param-value>false</param-value>
</context-param>

Very important, too, is to disable the serialization of state, serialization and deserialization of the component tree is a major performance hit.

<context-param>
<param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
<param-value>false</param-value>
</context-param>

If you find that memory is a constraining factor, then reducing the number of views stored in the session might help. The setting is controlled by:

<context-param>
<param-name>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</param-name>
<param-value>20</param-value>
<description>
Only applicable if state saving method is "server" (= default).
Defines the amount (default = 20) of the latest views are stored in session.
</description>
</context-param>


Sun-RI Performance Tuning

You should increase response buffer (to reduce reallocations at render time)

<context-param>
<param-name>com.sun.faces.responseBufferSize</param-name>
<param-value>500000</param-value>
</context-param>

Think about using an optimized serialization provider. The following example is a JBoss provider (code here)
)

<context-param>
<param-name>com.sun.faces.serializationProvider</param-name>
<param-value>org.jboss.web.jsf.integration.serialization.JBossSerializationProvider</param-value>
</context-param>



Facelets Performance Tuning

If you don't want to store too many state in either the server or the client, another possible
solution is to allow Facelets to build view before request processing instead of state saving.
But be warened about some unpredictable side effects. Use web.xml init parameter
together with the attribute.

<context-param>
<param-name>facelets.BUILD_BEFORE_RESTORE</param-name>
<param-value>true</param-value>
</context-param>

The ultimate solution for solving session state memory or performance problems is to create a custom
aceletsViewHandler subclass with special state handling where needed.
The custom handler could , for example, call buildView method instead of real restoreView
procedure for pages that typically do not need state (e.g. menue, navigation).

Facelets library in the "debug" mode stores information about
components and beans up to 5 times for an every user. You should disable this in production mode!

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


You should increase response buffer (to reduce reallocations at render time)

<context-param>
<param-name>com.sun.faces.responseBufferSize</param-name>
<param-value>500000</param-value>
</context-param>


You should also turn of the facelets refresh trigger in production environments.

<context-param>
<param-name>facelets.REFRESH_PERIOD</param-name>
<param-value>-1</param-value>
</context-param>



RichFaces Performance Tuning

Most filters use buffering for request processing. According to the
profile information, these buffers took big enough memory in the
application. Therefore you should limit the size for the RichFaces Ajax filter, too.

<init-param>
<param-name>maxRequestSize</param-name>
<param-value>100000</param-value>
</init-param>

For a production server, it makes sense to reduce the value to a real page
size or even remove that parameter at all.

Richfaces comes with some build in parsers to ‘tidy’ all HTML HTTP Responses so that they are valid
XHTML (thus XML compliant). This is needed as dynamic DOM updates in the browser need correct XML.

Of course, parsing HTML incurs a performance overhead.
This can be minimized by setting the forceparser setting to false. In that case only AJAX responses will be ‘tidied’. In the other case all JSF responses are ‘tidied’.

<filter>
<filter-name>richfaces</filter-name>
<display-name>RichFaces Filter</display-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
<init-param>
<param-name>forceparser</param-name>
<param-value>false</param-value>
</init-param>
</filter>


TIDY xml filter is DOM-based, thus it requires a lot of memory. It
would be better to use more optimized "NONE", "NEKO" ore "TIDY" should be the second and third best choice. The following example shows that ORDER parameter defines the order in which particular filter types are used for pages code correction.

<context-param>
<param-name>org.ajax4jsf.xmlparser.ORDER</param-name>
<param-value>NONE,NEKO,TIDY</param-value>
</context-param>

You can even set sets of pages for which the filters should apply. The following example applies the NEKO filter to all URLs.

<context-param>
<param-name>org.ajax4jsf.xmlparser.NEKO</param-name>
<param-value>.*\..*</param-value>
</context-param>


Before the version 3.1.3, RichFaces loaded styles and script on demand. I.e. files are loaded only if they are required on a particular page. Since RichFaces 3.1.3, it's possible to manage how the RichFaces script and style files are loaded to application.
Using the web.xml org.richfaces.LoadScriptStrategy setting, you can tell Richfaces to either:

* Load ALL script in one file.
* Load NONE scripts (you do it yourself instead - eg. in the manner prescribed by your book).
* Load scripts when needed (the DEFAULT).


<context-param>
<param-name>org.richfaces.LoadStyleStrategy</param-name>
<param-value>ALL</param-value>
</context-param>

<context-param>
<param-name>org.ajax4jsf.COMPRESS_SCRIPT</param-name>
<param-value>false</param-value>
</context-param>

If you use LoadScriptStrategy ALL, turn the compression off like it shown in the code snippet above


Some basic JSF performance principles

  • Never put logic into your getters. They are called multiple times and should only return something already populated by another method. For example if you are chaining drop-downs together use an a4j:support tag on the first one with an action attribute that loads the data which is then retrieved when you reRender the second one.
  • Use the ajaxSingle="true" unless you actually want to send the whole form back to the server.
  • Don't use a rich component if you only need a normal one. For example don't use rich:dataTable unless you are making use of some of the features that it has over and above h:dataTable.
  • Consider using immediate=true attributes on elements where you do not need validation
  • Avoid displaying large tables to user. Use pagination
  • Do not over complicate EL expressions, code them in Java in backing bean

Post a Comment

4Comments

Post a Comment