Search This Blog

Sunday 12 February 2012

To Singleton or Not To Singleton

Consider the below bean definition in our spring configuration file
<bean id="pBean" class="com.performer.Singer"/>
The above tells Spring to create an object of class Singer and assign it an id "pBean". Every time we request the container to provide us a bean with this particular id, the container will always return the same object. This is how Spring works by default. Every bean that we define in the configuration is a single unique bean. Or in other words, it is a singleton within the scope of the Spring container.
This is not same as the singleton design pattern. The singleton design pattern states that only one object of the class will created. Just One. Period. (OK, this is tweakable, but that is another story.) In case of Spring, however all requests for a bean with an id or names matching that bean definition will result in that one specific bean instance being returned. Thus you can not have two bean instances with id pBean in the Spring container. You can very well create infinite instances of the class Singer (at least until your heap space does not run out), but within Spring there will be only one bean with the name/id pBean.
While this design is perfectly suitable for DAO, Business Delegates or Service Locators we may wish for the very opposite behaviour in some cases. We could want that every time we request for a Bean Spring returns us a perfectly new and fresh bean. What we are wishing for here is a migration from Singleton behaviour to prototype behaviour.
Consider the bean definition below:
<bean id="prototypeBean"
      class="com.performer.Singer" scope="prototype" />
In this case we have added a scope attribute. The prototype value tells the Spring container that "every request for a bean with id 'prototypeBean' must result in a newly created bean". I tested the same with the below java code.
private void getPrototypeBeans(final BeanFactory beanFactory) {
    IPerformer singer1 = (IPerformer) beanFactory.getBean("prototypeBean");
    System.out.println("Prototype Bean 1 is " + singer1);
    IPerformer singer2 = (IPerformer) beanFactory.getBean("prototypeBean");
    System.out.println("Prototype Bean 2 is " + singer2);
    System.out.println("Are both beans different ? " + !singer1.equals(singer2));
}
The output is as below:
Creating a singer instance com.performer.Singer@1f4689e
Prototype Bean 1 is com.performer.Singer@1f4689e
Creating a singer instance com.performer.Singer@12f0999
Prototype Bean 2 is com.performer.Singer@12f0999
Are both beans different ? true
As can be seen the two request returned different objects. The default scope is singleton.
<bean id="singleBean"
      class="com.performer.Singer" scope="singleton" />

What would happen if dependencies of an object were prototype beans ?
Consider the xml fragment:
<bean id="prototypeBean"
     class="com.performer.Singer" scope="prototype" />
   
<bean id="prototypeBeanDependent1" class="com.performer.Singer" >
     <constructor-arg  ref="prototypeBean"></constructor-arg>
</bean> 
   
<bean id="prototypeBeanDependent2" class="com.performer.Singer" >
     <constructor-arg ref="prototypeBean"></constructor-arg>
</bean>
We have defined two instances of Singer - that both take a Singer as its parameter. In our case the parameter wired is of prototype scope.
And the java code to test the same:
public void getPrototypeBeanUsers(final BeanFactory beanFactory) {
    IPerformer singer1 = (IPerformer) beanFactory
            .getBean("prototypeBeanDependent1");
    IPerformer singer2 = (IPerformer) beanFactory
            .getBean("prototypeBeanDependent2");
    System.out.println("singer1 " + singer1 + " and " + singer2);
    IPerformer singer3 = (IPerformer) beanFactory
            .getBean("prototypeBeanDependent1");
    System.out.println("singletons are same ? " + singer1.equals(singer3));
}
The output on running the code is :
parameter is com.performer.Singer@1c99159
parameter is com.performer.Singer@d19bc8
singer1 com.performer.Singer@1630ab9 and com.performer.Singer@1551f60
singletons are same ? true
As can be seen the two singleton instances got their own instance of the prototype bean each.Thus each dependency resolved to a new bean instance.
These are not the only two scopes supported by Spring. There are a few more, but more on that later.

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete