Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way of making a singleton a Spring bean

Tags:

I am converting a singleton to a Spring bean, so that if the singleton fails to initialize, then entire web application's spring context doesn't load properly.

The advantage of making the Spring context not load properly, is that people will take notice and fix the configuration during deployment itself. As opposed to using 'non-spring bean' singleton: when that throws exception during initialization, nobody notices.. until a actual user complains of missing functionality.

My changes are working as expected.. but I am not sure if I am doing the right thing.
Any thoughts?

The code looks like this:

public class MySingleton {      private static MySingleton INSTANCE = null;     private MySingleton(){}   public static MySingleton getInstance(){     if(INSTANCE == null){         synchronized(MySingleton.class){             if(INSTANCE == null){                 try{                     doWork()                 }catch(Exception e){                     throw new IllegalStateException("xyz", e);                 }                 INSTANCE = new MySingleton();             }         }     }      return INSTANCE; }  private static void doWork() {     // do some work     }  } 

And in the spring config xml, the bean will be defined as:

<bean id="MySingletonBean"     class="com.MySingleton"     factory-method="getInstance" lazy-init="false" singleton="true"> </bean> 

Note: Most of this is similar to the strategy discussed in this article: http://springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html


Edit 1:

The classes that use this singleton, are not spring beans themselves.. they are just non-spring pojos, that I can't convert to spring. They must rely on getInstance() method get hold of the Singleton.


Edit 2: (copying a comment I made below into this description section) I am trying to target two things:

  1. I want Spring to initialize the singleton. So that if the initialization fails, then the application loading fails.
  2. I want the other classes be able to use classes without having to rely on contextAwareObj.getBean("MySingleton")


EDIT 3 (FINAL): I decided to make this class a singleton.. and am not making it a spring bean. If it fails to initialize, it will log something in the Log file.. hopefully the person doing deployment takes notice.... I abandoned the approach I mentioned earlier because I feel it will create a maintenance nightmare in future, so I had to pick between - singleton - or - spring bean. I chose singleton.
like image 619
rk2010 Avatar asked Jun 01 '11 17:06

rk2010


People also ask

How do you make a Spring singleton Bean?

The Message is a Spring bean managed by the Spring container. It has singleton scope. The @Scope("singleton") annotation is not necessary; the default scope is singleton if not specified. With the @PropertySource annotation we specify the properties file.

How singleton Bean works in Spring?

Spring singleton bean is described as 'per container per bean'. Singleton scope in Spring means that same object at same memory location will be returned to same bean id. If one creates multiple beans of different ids of the same class then container will return different objects to different ids.

How Spring singleton works is it a really singleton like Java singleton?

Summary. Spring Singleton is very different from Singleton pattern. Spring guarantees to create only one bean instance for given bean id definition per container. Singleton pattern ensures that one and only one instance is created per ClassLoader.

Are beans singletons?

By default, the scope of a bean is a singleton.


2 Answers

You must declare the INSTANCE field as volatile for double-checked locking to work correctly.

See Effective Java, Item 71.

like image 78
Matt Ball Avatar answered Oct 01 '22 01:10

Matt Ball


Why are you using singleton pattern on the first place? Just let Spring create bean for you (with default singleton scope) and... use it. Of course always somebody might create the bean by hand, but this was never a problem in my case.

Dependency injection and Spring-managed bean lifecycle will ease your life significantly (just see how many pitfalls you can avoid). Also note that exceptions thrown from c-tor or @PostContruct method will propagate and cause application context startup to fail as well.

UPDATE: I get your point. This is what came in to my mind:

@Service public class Singleton {      private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();      public Singleton() {         final Singleton previous = INSTANCE.getAndSet(this);         if(previous != null)             throw new IllegalStateException("Second singleton " + this + " created after " + previous);     }      public static Singleton getInstance() {         return INSTANCE.get();     }  } 

And let Spring do its job. You can use DI when possible and Singleton.getInstance() where you have to.

Also there are more hard-core solutions like compile-time AspectJ weaving and injecting Spring beans basically to everything.

like image 36
Tomasz Nurkiewicz Avatar answered Oct 01 '22 01:10

Tomasz Nurkiewicz