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
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:
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.
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.
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.
By default, the scope of a bean is a singleton.
You must declare the INSTANCE
field as volatile
for double-checked locking to work correctly.
See Effective Java, Item 71.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With