Making enterprise application 1 second faster

Posted by Tunde Michael | Sun Oct 16, 2016 03:41 PM | Viewed: 680

For web applications that are customer-facing (unlike in-house portals and administrative consoles), no stone should be left unturned in making the application one second faster as the number of customers can grow almost overnight (that’s your prayer right?).

Although scalability can mean a lot of things, I’m using it in this context to mean making your application just a little faster and with less stress on the server.

Below are 5 simple design hacks I try to remember. Your opinions are welcomed!

 

  1. Use a lot of @RequestScoped and very few  @SessionScoped beans

Using a lot of @SessionScoped beans increases memory footprint especially for clustered servers as the number of users of your application grows. Allan Lykke Christensen, Hazem Saleh and Zubin Wadia in their book Pro JSF and HTML5 even suggest one shouldn’t have more than one @SessionScoped bean in an entire application.

Make use of Facelet tags like f:viewParam, h:link, f:event, f:viewAction and designs that include preRenderView event method to handle data initialization before page load avoid having meany @SesssionScoped beans.

For example, implementing a page that displays list of products to users, say product-list.xhtml and when a user clicks on a product takes the user to product-detail.xhtml, the design below is what I will most likely choose:

A @RequestScoped backing bean that fetches the list of product as well as the selected product for the detail page:

// ProductController.java 
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;

@Named("productController")
@RequestScoped
public class ProductController {

private Long pid;
private List<Product> products;

   @PostConstruct
    public void loadProducts(){
        // load product list from the database here
    }

    /**
     * pre-render view event method to
     * fetch the selected product using the ID 
     * passed 
     */
    public void loadSelectedProduct(){
    
        // make your database call to load the selected product here
        
    }

   public List<Product> getProducts(){
    
       return products;
        
    }

}

The product list page having a UI:Repeat that renders some products beautifully with an h:link and f:param for navigation with the selected product ID to the detail page.

// product-list.xhtml
<ui:repeat value="#{productController.products}" var="product">
    <h:link value="View Product Detail" outcome="product-detail.xhtml">
         <f:param name="pid" value="#{product.id}"/>
    </h:link>
</ui:repeat>

and the product detail page with f:viewParam to grab the product ID and f:event pre-render view to call the methods that loads the details of the selected product from the database.

<f:metadata>
     <f:viewParam name="pid" value="#{productController.pid}" converter="productConverter"/>
     <f:event type="preRenderView" listener="#{productController.loadSelectedProduct()}"/>
</f:metadata>

This allows me not to save anything in the session and noticed that we still have the same number of trips to the database as what we would have had using @SessionScoped.

   

    2. JPA Indexing

Database indexing is probably the biggest thing in application’s performance enhancement I have heard about. Storage is cheap so the extra index column shouldn’t bother you or prevent you from indexing every column your application accesses frequently.

Thankfully we can even do this right on entity classes.

@Entity
@Table(name = "PRODUCT", indexes = {
    @Index(name = "idx_product_name", columnList = "PRODUCT_NAME", unique = false),
    @Index(name = "idx_product_type", columnList = "PRODUCT_TYPE", unique = false)})
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Product.findByName",
            query = "SELECT p FROM Product p WHERE p.productName =:name"),
    @NamedQuery(name = "Product.findByType",
            query = "SELECT p FROM Product p WHERE p.type =:type")
})
public class Product implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "PRODUCT_NAME")
    private String productName;
    @Column(name = "PRODUCT_TYPE")
    private String productType;

// getter and setter


}

 

    3. Never Make database calls in your getter methods. Ever!

Getter methods are sometimes called multiple times depending on how many times the variable is referenced on your page. They can be called as many as 10 times or more in one request, so never perform any expensive operation like making database calls in a getter method. Use @PostConstruct or preRenderView instead.

import javax.annotation.PostConstruct;

@PostConstruct
public void init() {
  // make your call here
}

 

    4.  Use @Asynchronous @EJB for trivial jobs

With Java EE 7, making a method asynchronous is as easy as just annotating any method of an @EJB with @Asynchronous (or the class itself and make all the methods @Asynchronous). 

For example, if you have an application that sends emails to users at signup or at every login (e.g bank apps), you dont want to keep the user waiting while you make the email sending call. Such methods can be made @Asynchronous 

import javax.ejb.Asynchronous;
import javax.ejb.Stateless;

/**
 *
 * @author Tunde Michael
 * 
 */
@Stateless
public class ProductBean {


    @Asynchronous
    public void sendEmail(){
   
        // send email here
   
    }
    
}

 

   5. Configure application @Resources in the application server

Configuring all application @Resources in the application server and just @Inject-ing them is something you really want to consider. Creating @Resources like email session, database connection etc. on the fly is resource intensive as application server can be configured to pool these resources, serve them for requests and return them back to the pool. 

 

Improving application performance certainly takes a whole lot more than these 5 things, we all have to start somewhere remember?

 

 

 

 


Share this post
facebook twitter googleplus linkedin





Comments (0)


Newsletter: Never miss a thing