Saturday 15 November 2014

How to make Spring beans thread-safe ?

Spring beans are singleton by default.
Singleton means bean identified by a particular bean id will have only one instance.

Consider the following code:
@Controller
public class MyServlet {

    @Autowired
    private HelloService service;

    @RequestMapping(value="/hello", method = RequestMethod.GET)
    public void sayHello(HttpServletRequest req, HttpServletResponse res) throws IOException {
        service.doStuff();
    }

}


public class HelloService {

    private int i = 1;

    public void doStuff() {
        System.out.println("Started " + i);
        i++;
        System.out.println(Thread.currentThread().getName() + " Done " + i);
    }
}
The output will be something like this:
32911580@qtp-28064776-0 - Started 1
7802158@qtp-28064776-2 - Started 2
32911580@qtp-28064776-0 - Done 3
7802158@qtp-28064776-2 - Done 3
This prove the "i" var is shared between multiple threads.
Now lets try to define the HelloService bean as prototype, like this
<bean id="helloService" class="my.package.HelloService" scope="prototype" />
In this case as well, the result is the same.
The only ways this can be solved is : move the declaration into doStuff() method, but it's not what we want - make the doStuff() method, but this means have locks
What I would like is have a new instance of HelloService on every call.
Since you have only one instance of MyServlet you will also have only one instance of HelloService.
One of the following spring scopes help: request A new instance for each HTTP request. session A new instance of the class for each new HttpSession created in a servlet container.
This will change the semantics of your code. If you declare the bean in the scope request your counter will always be 1.
So, to make bean thread-safe, make the bean definition scope as "request" or "session".

No comments:

Post a Comment