ICE09 . playing with java, scala, groovy and spring .

Playing with Spring

The Singleton Story

Posted by ice09 on May 26, 2008

As you may know, Spring is much about Singletons. By default, Spring beans are Singletons, ie. if you inject bean A in bean B, both of it are usually created once and reused all over your application.

Update (08.07.2008):
Inspired by Preston Lee’s comment, I wondered why the failures of Singletons (which I mostly agree with) in general do not affect my daily work.
I realized I am not really talking about Singletons in this post.
There is a brief and very good explanation of this topic here.
In short: this post is not about (VM-wide) Singletons in the usual sense, but about Spring’s default Bean-ID to (unique instance) bean mapping. Spring Beans are referenced by IDs and Spring by default returns the same, unique instance of a bean for each ID. This post discusses alternatives to Springs default unique instance handling. However, remember that these beans are no Singletons in the original meaning.

Consider the simplest example:


    <bean id="single" class="my.Single">
        <property name="prototype" ref="prototype" />
    </bean>

    <bean id="prototype" class="my.Prototype"></bean>

With this configuration, the following test app

package my;

public class Prototype {

    static int counter;

    Prototype() {
        System.out.println("Prototype constructor called.");
        counter++;
    }

    public String toString() {
        return String.valueOf(counter);
    }

}

the class which uses the Singleton:

package my;

public class Single {

    protected Prototype prototype;

    public void show() {
        System.out.println("prototype id: " + prototype);
    }

    public void setPrototype(Prototype prototype) {
        this.prototype = prototype;
    }

}

the main test class:

package my;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
        Single single = (Single) app.getBean("single");
        single.show();
        single.show();
        single.show();
        single.show();
    }

}

obviously prints out

Prototype constructor called.
prototype id: 1
prototype id: 1
prototype id: 1
prototype id: 1

Now, despite the apparently never occurring need of non-singleton beans, what can you do if you just want to have one, just for fun?

I, unbelievably, really faced the situation where I needed a non-singleton.

It was like this: you write some datatransfer stuff. It can happen that you need to parse Xml to get it done. You want to do this using a nice Singleton-Tool like this…


void transfer() {

  Document doc = this.xmlutils.createDocument();

  doSomethingWithDoc(doc);

}

…with xmlutils being nicely injected by Spring? Nice? No. Really ugly. Whatever sophisticated Xml-stuff you use, it almost certainly will be non-threadsafe.

So, yes, you really need some non-Singleton.

Searching for this will give you some pseudo-solutions like this.

Ok, I hate it. Definitely not what I want to have.
So, look at this one:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean id="prototype" class="my.Prototype" scope="prototype">
        <aop:scoped-proxy/>
    </bean>

    <bean id="single" class="my.Single">
        <property name="prototype" ref="prototype" />
    </bean>

</beans>

Now, that’s Springish, isn’t it? We proxy the object we inject and let Spring control the usage of our prototype bean, the scope of which we set with the attribute “scope” on the bean itself.

This prints out almost what we want:

Prototype constructor called.
Prototype constructor called.
prototype id: 2
Prototype constructor called.
prototype id: 3
Prototype constructor called.
prototype id: 4
Prototype constructor called.
prototype id: 5

Yes, a hundred bucks for the wise guy who can tell me how to omit the first (senseless) object instance – I just can’t figure it out. But since a prototype should per definition be lightweight, it just does not matter (to me) if there is one useless instance generated the first time.

So for me, that’s the best anti-singleton pattern.

Advertisements

4 Responses to “The Singleton Story”

  1. There are also a lot of reasons to avoid singletons in general.

  2. ice09 said

    There are good points in your post – I realized that this post is not about Singletons in the original meaning (http://en.wikipedia.org/wiki/Singleton_pattern) and updated it.

  3. miluch said

    Hi

    The one thing to note: prototypes created by are instance-per-call objects. Every time you execute any method on this kind of prototype you are dealing with different object underneath which IMO not only changes semantics of prototype, but make your java code look weird…

  4. […] Using an old example, I construed the case that accidentially instead of using a singleton, a prototype is used (once again a nice sample for Spring’s capabilities – changing one line changes the behaviour completely). […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: