07 - Singleton Session Beans

Singleton Session Beans

In this section we will introduce, how to create Singleton Session Beans and the various lifecycle events that are provided by the bean.

Bean Creation

Similar to Stateless beans, Singleton session beans also consists of 1 class, the bean class and 2 interfaces - local and remote. The class is required and the interfaces are optional.

Bean Class

Marking a class as a Singleton session bean requires annotating the class by the annotation @Singleton

AS an example:

import javax.ejb.Singleton;

@Singleton(name="LogInitializer")
public class LogInitializerBean {

}

Local Interface / Remote Interface

The rules that are apply to Stateless Session Beans are  also valid here, you use the same annotations (@Remote/@Local) to declare the remote and local interfaces and the same way  link the bean to the interfaces.

Example:

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Singleton;

@Local
interface LogInitializerLocal {

}

@Remote
interface LogInitializerRemote {

}

@Singleton(name="LogInitializer")
public class LogInitializerBean implements LogInitializerLocal, LogInitializerRemote {

}

Singleton Bean Lifecycle

The Singleton beans inherit the same Stateless session beans lifecycle.  The @PostConstruct methods and @PreDestroy methods are valid here also.

Singleton Bean Initialization

The default behavior for Singleton Session Beans initialization is, initializing the beans (all Singleton beans) before any client requests to other EJBs in the application.

For some reasons you may need to request from the container to initialize the bean once the application starts up (i.e. Log configuration initialization). In that case we have to add the annotation @Startup to our bean class

As an example:

import javax.ejb.Singleton;

@Startup
@Singleton(name="LogInitializer")
public class LogInitializerBean {

}

That way, our bean “LogInitializer” will be loaded and initialized once the application starts up and won’t wait till client requests to other EJBs in the application.

Singleton Bean Initialization

The default behavior for Singleton Session Beans initialization is, initializing the beans (all Singleton beans) before any client requests to other EJBs in the application.

For some reasons you may need to request from the container to initialize the bean once the application starts up (i.e. Log configuration initialization). In that case we have to add the annotation @Startup to our bean class

As an example:

import javax.ejb.Singleton;

@Startup
@Singleton(name="LogInitializer")
public class LogInitializerBean {

}

That way, our bean “LogInitializer” will be loaded and initialized once the application starts up and won’t wait till client requests to other EJBs in the application.

Dependency between Singleton Beans

Suppose we have 2 Singleton beans in an EJB application, one for log initialization “LogInitializerBean” and the other one for initializing application backend jobs “BackEndJobsInitializerBean. Now as expected, the 2nd bean will need to log some logs in our logs repository about the initialization of the backend Jobs. That requires the LogInitializerBean to start and get initialized before the BackEndJobsInitializerBean gets initialized. The initialization order of application Singleton beans by default is left to the container, and for cases when we need to specify the order for beans initialization, we use the annotation @DependsOn to set initialization dependency between application Singleton beans.

As an example, our beans will look like the following:

import javax.ejb.DependsOn;
import javax.ejb.Singleton;

@Singleton(name="LogInitializer")
class LogInitializerBean {

}

@Singleton(name="BackEndJobsInitializer")
@DependsOn("LogInitializer")
class BackEndJobsInitializerBean {

}

That way, the container will always initialize the bean LogInitializerBean before the bean BackEndJobsInitializerBean.

Singleton Beans Concurrency Management

Now, as you may have guessed, as we have only one instance of the bean and the bean instance is supposed to serve multiple simultaneous requests, we will  have a concurrency issue.  EJB3 provides a service for managing concurrent access on singleton beans.

The container will provide 2 ways of locking, READ (shared) lock and WRITE lock (exclusive). The default lock mechanism is the WRITE lock. EJB3 uses annotation @Lock to specify lock mechanism.

In READ lock, all simultaneous invocations of methods with the READ lock are allowed, but in WRITE lock, all simultaneous invocations of methods with READ/WRITE lock are blocked.

Example, consider the following bean:

 
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class ItemsListBean {

     @Lock(LockType.WRITE)
     public void updateList(String newItem) {
        //
     }

     @Lock(LockType.READ)
     public int listSize() {
        return 0;
     }
     public void doAction() {
   
     }    
}

Now during the invocation of the method “updateList”, all other methods invocations will be blocked until this method finishes execution.  But in case of the “listSize” method,  all concurrent access to the method will be allowed in case no other invocations for “updateList” and “doAction” take place.

For the “doAction” method, the container will provide WRITE access for the method as this is the default access type for Singleton session beans.

The line @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) indicates that we want  to use Container Concurrency Management, this is the default one and we will get the same behavior in case we removed that line.

You may specify locking timeouts for WRITE lock mechanism, as an example:

@Lock(LockType.WRITE)
@AccessTimeout(unit=TimeUnit.SECONDS, value=10)
public void updateList(String newItem) {
    //
}

Now, the method will block concurrent access for WRITE/READ lock methods for 10 seconds and in case the 10 seconds passes and the method doesn’t finish the execution, then a ConcurrentAccessTimeoutExceptionexecption will be thrown.

All of the above is considered a type of Container Concurrency Management. Another type of concurrency management is the Bean Concurrency Management where it is left to the developer to handle the concurrency management using the provided lock mechanism provided by the Java JDK.  To enable Bean Concurrency Management use the following:

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class ItemsListBean {

 

Like us on Facebook