Environment:
If you would like to use a JavaEE application server, i would go with TomEE.
It's the fastest and smallest application server available and already comes with Apache MyFaces as JSF implementation and Apache OpenWebBeans as CDI implementation.
There are already really good benchmarks available why we should choose MyFaces over Mojarra and OpenWebBeans over Weld:
Understanding JSF 2.0 Performance – Part 1
Understanding JSF 2.0 Performance – Part 2
Understanding JSF 2.0 Performance – Part 3
CDI Performance
So if you just use a plain servlet container like Tomcat or Jetty, i would also use MyFaces and OpenWebBeans.
In the past it was also a good performance boost if you use JUEL over Tomcat's EL implementation - sadly JUEL doesn't implement EL 3.0.
Configuration:
- Common settings:
<context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Production</param-value> </context-param> <context-param> <param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name> <param-value>-1</param-value> </context-param> <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>server</param-value> </context-param>
<context-param> <param-name>org.apache.myfaces.CACHE_EL_EXPRESSIONS</param-name> <param-value>alwaysRecompile</param-value> </context-param>
<context-param> <param-name>org.apache.myfaces.SUPPORT_JSP_AND_FACES_EL</param-name> <param-value>false</param-value> </context-param> <!-- NOTE: the ExpressionFactory might differ e.g. on Glassfish or Wildfly. This parameter is optional since MyFaces 2.3.3. --> <context-param> <param-name>org.apache.myfaces.EXPRESSION_FACTORY</param-name> <param-value>org.apache.el.ExpressionFactoryImpl</param-value> </context-param>
<context-param> <param-name>org.apache.myfaces.SUPPORT_MANAGED_BEANS</param-name> <param-value>false</param-value> </context-param>
<context-param> <param-name>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</param-name> <param-value>15</param-value> </context-param> <context-param> <param-name>org.apache.myfaces.NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION</param-name> <param-value>3</param-value> </context-param>
<context-param> <param-name>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</param-name> <param-value>false</param-value> </context-param>
<context-param> <param-name>primefaces.SUBMIT</param-name> <param-value>partial</param-value> </context-param>
<context-param> <param-name>primefaces.MOVE_SCRIPTS_TO_BOTTOM</param-name> <param-value>true</param-value> </context-param>
<context-param> <param-name>org.apache.myfaces.CHECK_ID_PRODUCTION_MODE</param-name> <param-value>false</param-value> </context-param> <context-param> <param-name>org.apache.myfaces.EARLY_FLUSH_ENABLED</param-name> <param-value>true</param-value> </context-param>
Patterns:
- Correctly define update/render and process/execute! Often this is a huge improvement as many times the whole form is updated instead only a small part. But i also prefer maintainability over performance here.
- If you don't use ViewScoped beans, it's a good but small improvement to mark the view as stateless via transient=true.
- Try using HTML over JSF tags.
- Especially avoid using h:outputText if you don't need the escaping. Just use EL expressions inside your xhtml template.
- The same applies for some other components like p:outputPanel. Just use a plain div. If you need to make it updateable, you can still use "passtrough elements" (<div jsf:id="...">...</div>)
- Never put logic in getters because they can be called multiple times - especially for the rendered attribute!
- Avoid logic (like inline if-statements) in EL expression! It's better to move those logic into the bean. It's faster and often easier to read and maintain.
- Prefer AJAX over a full postback!
- If you have many p:outputLabel's on the page and you know that the input field is required or not, it's a good performance improvemet to set the input to required=true or the outputLabel to indicateRequired=true|false. The default value for indicateRequired since 6.2 is auto, which tries to lookup BeanValidation constrains to check if @NotNull|@NotEmpty|@NotBlank are defined.
- Cache data, which is required multiple times in the same view, in @RequestScoped beans.
- Avoid missusing @SessionScoped, @ViewScoped and other long living scopes if not really required.
- Try to put only small amount of data in such long living beans. Sometimes a small flag or id of an entity is enough information. Often people put many entities in such long living beans. One of my patterns is to split beans into *Controllers (@RequestScoped) and *StateHolders (@ViewScoped, @ViewAccessScoped). *StateHolders are just data containers.