Fun with CDI: Singletone pattern using Dependency Injection

Every Java developer knows the classic single-tone pattern. Here shown using the laziest implementation possible. Source and more information about this, see  http://en.wikipedia.org/wiki/Singleton_pattern

public class Singleton {

   // Private constructor prevents instantiation
   // from other classes
   private Singleton() {
   }

   /**
   * SingletonHolder is loaded on the first execution
   * of Singleton.getInstance() or the first access
   * to SingletonHolder.INSTANCE, not before.
   */
   private static class SingletonHolder {
       public static final Singleton INSTANCE = new Singleton();
   }

   public static Singleton getInstance() {
      return SingletonHolder.INSTANCE;
   }
}
:
:
// Get the instance:
Singleton st=Singleton.getInstance();
:

Using @Singleton or @ApplicationScoped introduced with Java EE, this pattern has become quite obsolete.

However, for the fun, let’s use Context and Dependency Injection (CDI) introduced with Java EE 6, to replace the classic “getInstance()” by injection.

All we need is to create a Qualifier and to decorate the “getInstance()” in order to transform it into a Producer. The Qualifier is needed in order to unambiguously define the “getInstance()” as injection source of the “RegistrySingletone” instance and not the class itself (“new RegistrySingletone()”).

package beex1.singletone;

import java.io.Serializable;
import javax.enterprise.inject.Produces;

public class RegistrySingletone implements Serializable {

 // Private constructor prevents instantiation from other classes
 private RegistrySingletone() {
    System.out.println("*** RegistrySingletone: Constructor: "+this);
 }

 /**
 * RegistrySingletonHolder is loaded on the first execution of
 * Singleton.getInstance() or the first access to
 * SingletonHolder.INSTANCE, not before.
 * See http://en.wikipedia.org/wiki/Singleton_pattern
 */
 private static class RegistrySingletonHolder {
    public static final RegistrySingletone INSTANCE =
                                   new RegistrySingletone();
 }

 /**
 * The classic getInstance() is now invoked by injection.
 */
 @Produces @RegistrySingletoneProducer
 /* package private */
 static RegistrySingletone getInstance() {
    System.out.println("*** RegistrySingletone: getInstance/Producer: "+
                                     RegistrySingletonHolder.INSTANCE);
    return RegistrySingletonHolder.INSTANCE;
 }
}
… and the qualifier:

package beex1.singletone;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;

@Qualifier
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD,
          ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
//
public @interface RegistrySingletoneProducer {
}

To test the magic, we implement a small backing bean…

package beex1.client;

import beex1.singletone.RegistrySingletoneProducer;
import beex1.singletone.RegistrySingletone;

import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;

@Named
@SessionScoped
public class SingletoneUserBean implements Serializable {

 @Inject @RegistrySingletoneProducer
 RegistrySingletone registrySingletone;

 public SingletoneUserBean() {
    System.out.println("+++ SingletoneUserBean: Constructor");
 }

 @PostConstruct
 public void myInit() {
    System.out.println("+++ SingletoneUserBean: PostConstruct");
 }

 @PreDestroy
 public void myDestroy() {
    System.out.println("+++ SingletoneUserBean: PreDestroy");
 }

 public String getTest() {
    System.out.println("+++ SingletoneUserBean: Injected Singletone:"+
                                                  registrySingletone);
    return "test";
 }
}

… and the index.xhtml (JSF2) page…

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:h="http://java.sun.com/jsf/html">
  <h:head>
    <title>Facelet Title</title>
  </h:head>
  <h:body>
    Singletone Bean Instance - <h:outputText
                    value="#{singletoneUserBean.test}"/>
  </h:body>
</html>

Invoking this page from multiple browsers (to have a new HTML session each time) gets us the following result:

INFO: +++ SingletoneUserBean: Constructor
INFO: *** RegistrySingletone: Constructor:
                   beex1.singletone.RegistrySingletone@900995
INFO: *** RegistrySingletone: getInstance/Producer:
                   beex1.singletone.RegistrySingletone@900995
INFO: +++ SingletoneUserBean: PostConstruct
INFO: +++ SingletoneUserBean: Injected Singletone:
                   beex1.singletone.RegistrySingletone@900995
INFO: +++ SingletoneUserBean: Constructor
INFO: *** RegistrySingletone: getInstance/Producer:
                   beex1.singletone.RegistrySingletone@900995
INFO: +++ SingletoneUserBean: PostConstruct
INFO: +++ SingletoneUserBean: Injected Singletone:
                   beex1.singletone.RegistrySingletone@900995
INFO: +++ SingletoneUserBean: Constructor
INFO: *** RegistrySingletone: getInstance/Producer:
                   beex1.singletone.RegistrySingletone@900995
INFO: +++ SingletoneUserBean: PostConstruct
INFO: +++ SingletoneUserBean: Injected Singletone:
                   beex1.singletone.RegistrySingletone@900995

Tested with Netbeans 6.9.1, Glassfish 3.0.1, Weld 1.0.1 SP3. Note you don’t need a Java EE 6 container. Including Weld into your Java SE project should be sufficient.

Lessions learned: We see that CDI handles very well static methods. Omitting the static keyword would have Weld creating an instance of the “RegistrySingletone” for each injection just to be able to call the “getInstance()” method. Using static, this isn’t the case, no object is instantiated.

Leave a Reply

Your email address will not be published. Required fields are marked *