Tuesday, June 25, 2013

Spring singletons - a potential source of error

When you create a Spring bean and do nothing special it will be a singleton as described in the documentation. Such a declaration might look like this:

package org.saabye_pedersen.kim;

@Component
public class ExampleBean {
    
    public String getMessage() {
        return "Hello world!";
    }

}
With a XML config like this:



 


If we run this code:
public class Main {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("file:src/main/resources/META-INF/spring/app-context.xml");
        ExampleBean bean = ctx.getBean(ExampleBean.class);
        String message = bean.getMessage();
        System.err.println(message);


        ExampleBean beanAgain = ctx.getBean(ExampleBean.class);
        message = beanAgain.getMessage();
        System.err.println(message);
    }

}
the output will be:
Hello World!
Hello World!
So far so good. Everything is fine and dandy. But what happens if we change the class to this:
@Component
public class ExampleBean {

    private int aMember = 1;

    public String getMessage() {
        String tmp = "Hello world! " + aMember++;
        return tmp;
    }
}
What will main method of the Main class print this time? The answer is:
Hello world! 1
Hello world! 2
Did you expect this instead?:
Hello world! 1
Hello world! 1
The result is hopefully not surprising, yet I have seen much code with singletons containing code that manipulates instance members in a way that will fail. For instance this will only work in the first invocation:
@Component
public class AnotherExampleBean {

    private int sum = 0;

    public int calcSumOfProvidedInts(int[] intsToSum) {

        for (int i : intsToSum) {
            sum += i;
        }

        return sum;
    }
}