Singleton EJB tutorial

One of the most interesting news of Java EE 6 is the Singleton annotation which can be used to mark your EJB as Singleton services.
As the name implies a javax.ejb.Singleton is a session bean with a guarantee that there is at most one instance in the application. Until now if you wanted to expose a Service as Singleton you had to use either Service POJOS (See an article here JBoss MBeans POJO ) or tweak the EJB pool maximum size.

All of these approach worked, however they were not portable because they used JBoss annotations/configuration to do the trick.

Now with the latest release of JBoss 6 M3 you can use a Java EE 6 full compliant solution. Making an EJB as Singleton is pretty easy: just add the java.ejb.Singleton annotation and that’s all.

Here’s an example:

package sample;

import javax.annotation.PostConstruct;
import javax.ejb.Remote;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import org.jboss.ejb3.annotation.RemoteBinding;

@Singleton

@Remote
@RemoteBinding(jndiBinding = "SingletonBean")
@Startup

public class SingletonBean implements SingletonItf {
    int total;

    @PostConstruct
    private void startup() {
        System.out.println("Singleton inited!");
    }

    
    public void add(int i) {
        
        total += i;

    }

    
    public int getTotal() {
        
        return total;
    }
}

In this example, the EJB exposes a trivial add(int i) method which increments a counter. Since there will be just one instance of SingletonBean, the total variable can be used across client calls.

Notice also the @Startup annotation which is not mandatory but can be used to signal to the container to invoke the @PostConstruct method just after the Bean has been created. So, if you need a proper Bean initialization, just add a @Startup annotation at Class level and a @PostConstruct at method level.

Testing the EJB is pretty simple, here’s a remote client example:

import java.util.Properties;

import javax.naming.InitialContext;
import sample.SingletonItf;


public class TestEJB  {
    public static void main(String args[])throws Exception {
        Properties properties = new Properties();    
        properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");      properties.put("java.naming.factory.url.pkgs",        "org.jboss.naming:org.jnp.interfaces");    
        properties.put("java.naming.provider.url", "jnp://localhost:1099");    
        
        InitialContext ctx = new InitialContext(properties);
        SingletonItf ejb = (SingletonItf) ctx.lookup("SingletonBean");
        ejb.add(30);
        System.out.println("Total is "+ejb.getTotal());

    }
}

Dealing with synchronization

At this point you might wonder how does the container deals with synchronization ? that is, what happens if two client invoke the Singleton cuncurrently ? If you deploy the EJB as in the example above, each method of the Bean will be synchronized, that is, if there’s a thread executing one method the other thread will wait for the first thread to release the lock.

That’s much the same way as if you add mark a method as synchronized in standard Java SE.

You can however apply fine tuning locking strategies so that some methods are allowed to be executed cuncurrently and some not: see the modified example:

public class SingletonBean implements SingletonItf {
    int total;

    @PostConstruct
    private void startup() {
        System.out.println("Singleton inited!");
    }

    @Lock(LockType.WRITE)
    public void add(int i) {
        
        total += i;

    }

    @Lock(LockType.READ)
    public int getTotal() {
    
        return total;
    }
}