I'm working on a WebApp using JSF 2.2 + Primefaces... project is growing fast, and first performance test was very poor (due to my poor knowledge on JSF lifecycle in combination to non-functional requirements - i.e. fully ajax website), then we could improve a little but results still, are not as expected. (We are having a time of 300~1500 ms depending on the action, idea is to have a performance around 500ms, give or take). Mainly the Restore View phase and the Render Response are the time consumers (on other phases, time spent is worthless). For some actions, Invoke Application also takes time (due to DB calls).
After reading lots of articles on the web, there were a lot of awesome tips to be taken into account (many of course from StackOverflow) such as:
- Improving DB queries
we have some complex ones which are done with two Hibernate Criteria queries so we have to work here. (maybe use pure SQL queries, and on complex ones use sub-querying?)
- Never defining business logic on Bean's getters
Got It!
- Setting the appropriate scopes to bean and storing on them nothing more than the necessary stuff
We have a full ajax site, so View Scoped are almost as Session Scoped to us, we are using the SessionBeans as a sort of 'Cache' to store key data which we don't want to get from DB every time + define businesses logic here.
- Choosing the right State saving method of JSF - Client Vs Server
For this, I have to research some more, check on the possibilities with their pros and cons, then test performance on each one.
So far very clear, now some extra tips on which I have some doubts.
- Use vanilla HTML as much as possible, and preferably use h: tags rather than p: tags
Plain HTML is clear and make sense, now between h: and p: how much is it worthy? For example.
<p:commandButton value="Value"
styleClass="class"
actionListener="#{myBean.doStuff()}"
ajax="true" process="@form" update="@form"
onsuccess="jsFunction()" />
vs
<h:commandButton value="Value"
styleClass="class"
actionListener="#{myBean.doStuff()}" >
<f:ajax execute="@form" render="@form" event="onclick" />
</h:commandButton>
or
<ui:fragment... vs <p:fragment...
or
<p:outputLabel value="#{myBean.value}" rendered="#{myBean.shouldRender}" />
vs
<ui:fragment rendered="#{myBean.shouldRender}">
<label>#{myBean.value}</label>
</ui:fragment>
I've been using a mix of Primefaces with Jsf tags and some plain HTML here and there for a while now.(mainly PF due to their component's features) I now that plain HTML will always be faster, but between JSF and another Framework? If I go for this, changing it will take plenty of time and I wouldn't like the outcome of knowing it doesn't make a relevant difference at all.
- Custom Facelets tags vs Composite Components
I think here's the key. Still have some doubts about their differences, on the implementation of both, CC are pretty simple and flexible to use but have the disadvantage that they are fully included on the ViewTree and JSF re-generates for each request (if I'm not mistaken), while custom tags seems a little bit more complex to use (not that much) but has the advantage that only what is actually rendered is included on the ViewTree and nothing more, making the RESTORE VIEW less time consuming. We have several composite components and none Facelets Tags, so here it will be much of the work to do. I still haven't found a good article explaining differences on them, when one should be used and when the other one (have read that for inputs, messages use TAGS and for more complex things CC). If the idea is to prefer tags vs CC, which would be the case on which I would have no option rather than using CC? Is it ok to use custom tags inside CC to make them lighter to JSF for processing them?
I'm about to get into a journey of modifying hole project in order to get a better performance which will take me a couple of days, idea is to get better results this time; so every tip, advice and suggestion is very welcomed! Thanks for your time guys!
There are a couple of things you can do to improve performance of your screens
To see if your contents are already usign gzip and cache, In your Google Chrome Browser -> right click on your screen -> inspect -> click network tab -> refresh your screen. Click on the images, icons, stylesheets and see if you see following in response header
Cache-Control:max-age=2592000
if the status of element is 304 (coming from cache)
Content-Encoding:gzip
if the status of element is 200
RenderResponse takes 98% of your time because... that's what JSF mainly does. I'd be worried if JSF dedicated 50% of a request's processing time to do things other than rendering the response! You need to dig deeper. Consider this example.
Say you have a page that displays a table. You use the p:dataTable PrimeFaces component, like this:
<h:html>
<h:body>
<p:dataTable value="#{myBean.data}">
</p:dataTable>
</h:body>
</h:html>
And you have this @ManagedBean
:
@ManagedBean(name="myBean")
public class MyBean {
public List<MyObject> getData() {
return // fetch list from database;
}
}
Every time getData()
is called, there's a database access, and that time adds to the global time of the render phase. Moreover, the rendering of p:dataTable might require many calls to getData.
Again, you need to dig deeper into you application and detect where exactly, during the render phase, is time being spent. In my experience, naive implementations of @ManagedBean
s have a lot of database-querying code in the same getters referenced in the xhtml
s, like in my previous example. JSF (or a component like PrimeFaces' p:dataTable) might invoke those getters many times while rendering a single xhtml. A common strategy is fetching data only once, using the preRenderView event, like this:
In your xhtml:
<h:html>
<f:metadata>
<f:event type="preRenderView" listener="#{myBean.fetchDAta}"/>
</f:metadata>
<h:body>
<p:dataTable value="#{myBean.data}">
</p:dataTable>
</h:body>
</h:html>
In your managed bean:
@ManagedBean(name="myBean")
public class MyBean {
private List<MyObject> data;
public void fetchData() {
data = // fetch data from database.
}
public List<MyObject> getData() {
return data;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With