Singletons

One of the long-standing limitations of the EJB component model has been the inability to easily share application-scoped state. The EJB 3.1 Singleton component solves this problem.

A Singleton is a new kind of Session bean that is guaranteed to be instantiated once per application (per server instance). A Singleton bean instance lives for the duration of its associated container. Singletons have much in common with Stateful and Stateless Session beans :

  • Support for Container Managed Transactions (CMT) and Bean Managed Transactions (BMT)
  • Ability to expose multiple independent client views ( No-interface, Local, Remote, Web Service )
  • EJB reference based client programming model
  • Access to container services for injection, resource manager access , timers, etc.

Here's a simple Singleton that provides some read-only configuration data :


   1:  @Singleton
   2:  public class SharedConfig {
   3:            
   4:    private ConfigData config;
   5:    
   6:    @PostConstruct 
   7:    private void init() {
   8:      // initialize configuration data
   9:      config = ...;
  10:    }
  11:       
  12:    public int getPropertyA() {
  13:      return config.propertyA;
  14:    }
  15:  }

It's common for such shared state to be very large and have significant setup costs. Storing it within a singleton guarantees efficient use of memory and avoids the overhead of redundant initialization.

Client access is easy -- just acquire a Singleton EJB reference through injection or lookup :


   1:  @Stateless
   2:  public class FooBean {
   3:   
   4:    @EJB
   5:    private SharedConfig configBean;
   6:   
   7:    public void foo() {
   8:      int propertyA = configBean.getPropertyA();
   9:      ...
  10:    }
  11:  }

Reusing the standard session bean client view for Singletons has the added benefit of allowing access from many kinds of clients, not just other EJB components. This makes it easy to share state between the web components and EJB components in an application.

Concurrency is another important Singleton topic. Singletons are intended to be called by many clients at once. However, the EJB component model has always guaranteed that no more than one thread has access to a particular bean instance at a time. Offering only that threading policy for Singletons would ensure correctness but would be too restrictive from a performance standpoint.

In order to balance these concerns, the container ensures single-threaded access to Singletons by default, but the developer can choose between two additional concurrency policies : container-managed concurrency (CMC) and bean-managed concurrency (BMC).

With CMC, developers use method-level shared/exclusive locks to tell the container when it's OK for multiple callers to have concurrent access to the bean instance. An invocation that can not proceed due to locks is blocked until it can make forward progress or until an optionally-specified timeout is reached. In CMC mode, the container is still in control but the fact that instance-level concurrency can occur boosts performance. The developer is freed from using Java SE level synchronization primitives to protect instance state.

Here's a slightly modified version of the previous Singleton example, this time using CMC :


   1:  @Singleton
   2:  public class SharedConfig {
   3:            
   4:    private ConfigData config; 
   5:       
   6:    @Lock(LockType.READ)
   7:    public int getPropertyA() {
   8:      return config.propertyA;
   9:    }
  10:   
  11:    @PostConstruct 
  12:    private void init() {
  13:      // initialize configuration data
  14:      config = ...;
  15:    }
  16:  }

The @Lock(LockType.READ) annotation tells the container that any number of concurrent invocations can access getPropertyA() at the same time. This is the simplest case since this bean has immutable state. If it supported updates, it would look like this :


   1:  @Singleton
   2:  public class SharedConfig {
   3:            
   4:    private ConfigData config; 
   5:       
   6:    @Lock(LockType.READ)
   7:    public int getPropertyA() {
   8:      return config.propertyA;
   9:    }
  10:   
  11:    @Lock(LockType.WRITE)
  12:    public void update(...) {
  13:      // update state
  14:      ...
  15:    }
  16:   
  17:    @PostConstruct 
  18:    private void init() {
  19:      // initialize configuration data
  20:      config = ...;
  21:    }
  22:  }

Here, the container guarantees that an invocation on the update() method will only proceed when it can have exclusive access to the bean instance.

In BMC mode, the bean developer has full control over concurrency. The container passes all invocation threads directly through to the bean instance, just as in the Servlet programming model. It's the developer's responsibility to ensure the integrity of the instance state however possible, including through the use of Java SE level synchronization primitives. Here's the previous example using BMC mode :


   1:  @Singleton
   2:  @ConcurrencyManagement(ConcurrencyManagementType.BEAN)
   3:  public class SharedConfig {
   4:            
   5:    private ConfigData config; 
   6:       
   7:    synchronized public int getPropertyA() {
   8:      return config.propertyA;
   9:    }
  10:   
  11:    synchronized public void update(...) {
  12:      // update state
  13:      ...
  14:    }
  15:   
  16:    @PostConstruct 
  17:    private void init() {
  18:      // initialize configuration data
  19:      config = ...;
  20:    }
  21:  } 

This is an oversimplified example of BMC merely intended to show the required annotations and an example of Java SE level synchronization appearing directly in the bean class. Typically the locking would not be applied at the method level since that approach does not offer significant benefit over CMC mode. Much like the tradeoffs associated with using Bean Managed Transactions, Bean Managed Concurrency mode offers finer-grained control at the cost of added code complexity.

That's a brief introduction to Singletons. I'll be writing a follow-up post about how they can provide another piece of previously missing EJB component functionality : application startup and shutdown callbacks.

Comments:

Hi Ken,

thanks for this post. We appreciate that now there are singleton beans.
We process an ordered message flow using message driven beans and wonder
whether the EJB spec could also support singleton message driven beans.
E.g. JBoss supports such a configuration for a while: There is a dedicated
thread pool per MDB serving the onMessage() request and if the size of this pool is fixed to one, we have the singleton behaviour.

Please, could you suggest a good way to achieve this using normal MDB and singleton session beans in EJB 3.1?

Thanks, Jörg

Posted by Jörg Thönnes on January 12, 2010 at 09:09 PM EST #

Hi Jorg,

Thanks for the comments. It's unlikely that message-ordering requirements would be added to the MDB container, since doing so removes the efficiency gains of concurrent message delivery. Message ordering semantics are better handled at the application level, typically through the use of a relational database. That also allows for the application to be deployed to a cluster without changing its behavior, which is an important aspect of the EJB component programming model.

It's true that many vendors provide configuration which allows the developer to achieve single-threaded message delivery. However, writing an MDB component with this expectation is non-portable.

Posted by Ken Saks on January 13, 2010 at 02:19 AM EST #

Hi Ken,

thanks for the quick reply. Using a relational database does not seem appropriate to us since the performance is important to us. We connect
banks to stock exchanges and process both order, trade and market data
through MDBs. If e.g. an insert message is overtaken by a delete message
this could cause dramatic errors (and lost of money).

Currently, we implement this on GF v2.1.1 by configuring the MDB pool to
allow exactly one instance. To be honest, we did not find any other
useful way to force the MDBs to process the messages in order.

Are singleton session beans of any help here? Could singleton session bean
synchronize the message order for an MDB? Any hints and thoughts are very
welcome.

Thanks, Jörg

Posted by Jörg Thönnes on January 13, 2010 at 11:26 AM EST #

Hi Jorg,

Singleton beans wouldn't help for what you're trying to do. There isn't any special relationship between the message processing behavior in the message-driven bean container and Singletons.

--ken

Posted by Ken Saks on January 19, 2010 at 07:06 AM EST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Ken Saks is the Spec Lead for Enterprise JavaBeans (EJB) 3.1 and a Senior Staff Engineer in the Java Platform, Enterprise Edition team at SUN.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today