Spring: Serving Multiple Requests With the Singleton Bean
Read more about serving multiple requests with Spring beans!
Join the DZone community and get the full member experience.
Join For FreeWhen I first started to learn Spring, two “difficult” questions crossed my mind:
- How is a singleton bean created?
- And how is that single bean auto-wired in different classes?
You may also like: Spring Bean Lifecycle
Imagine the following scenario:
There are two users. One of them wants to log in, and another one wants to create a report in our application at the same time. And both login
and createReport
methods use the userService
bean, which is scoped as a singleton. In this case, do those methods use that singleton bean sequentially? Otherwise, how does a singleton bean serve multiple requests concurrently?
Answering these questions was not as difficult as I originally thought. It was only needed to clarify simple-yet-important points. That is why I will try to describe them with basic code examples. Let’s begin:
1. It would be useful if we talk about Spring containers first. Because I think this will help you to describe the process better in your mind.
The Spring container creates beans in it. After creating needed beans, it injects dependencies of them. The container gets its instructions by reading configuration metadata (XML or Java annotations). So after the Spring container is initialized, your application is ready to use as described in the following picture:
When you define a bean definition like the following, you tell the container that it must create only one instance for that bean definition in the container:
<bean id=”accountDao” class=”…” scope=”singleton”/>
This single instance is stored in a cache of such singleton beans. Then, the Spring container returns this cached object to all requests and references for beans with that bean definition:
If we want to show the above example with a new()
operator for describing a simplified view of what Spring container does on startup of the application, we can code as following:
xxxxxxxxxx
UserService userService = new UserService();
UserController userController = new UserController();
userController.userService = userService;
ReportController reportController = new ReportController();
reportController.userService = userService
I think there is no need for more explanation. The example above shows how the same bean is used for different classes.
2. In Spring, every request is executed in a separate thread. For example, when two users want to log in at the same time, the JVM creates two threads: one thread for the first user and another one for the second user.
For showing this, the following simple code snippet can help us. If you sent two requests for login method concurrently and print current thread name (which the requested login method is executed), you will see two different thread names there. This shows us every request is executed in a separate thread:
xxxxxxxxxx
public class UserController {
private UserService userService;
value = "/login/{username}") (
public User login( (value = "username") String username){
System.out.println(Thread.currentThread().getName() + " ----------- " + username + " ----------- " + new Date());
return userService.login(username);
}
}
xxxxxxxxxx
Result:
http-nio-8080-exec-9 ----------- Ben ---------- Sat Nov 23 20:01:35
http-nio-8080-exec-6 ----------- Kate ---------- Sat Nov 23 20:01:35
You can send concurrent requests with help of curl command like this:
curl http://localhost:8080/login/Ben & curl http://localhost:8080/login/Kate
And these threads work with the singleton bean separately. How? Let’s speak about memory allocation in Java a little bit.
In Java, every object is created in heap. Heap has globally shared memory. That is why every thread can access objects in heap.
But the stack is used for the execution of only one thread. In that thread, when a method is invoked, a new block is created in the stack in LIFO( Last-In-First-Out) order. This block holds local primitive values and references to other objects in the method. And the stack memory cannot be accessed by other threads.
So, when we create a singleton bean, it resides in heap. Because the heap is accessible from anywhere in the application, every created thread can point to that singleton bean. And how is this happening? When the thread requests the singleton bean, it is going to refer (with help of reference variable in the stack) to the bytecode of singleton bean in heap. So, multiple threads can refer to the singleton bean at the same time. The compiler is going to point to the same bytecode and simply execute it and store method-specific values in corresponding blocks in stack separately. There is no restriction preventing the compiler from doing this. The only restriction that the singleton class puts on the JVM is that it can have only one instance of this class in the heap. And this is why ideal singleton bean must be stateless. Otherwise, concurrency issues can occur.
I hope this will help you to understand the process clearly. If you have any questions, please let me know in the comments.
Happy coding!
Further Reading
Opinions expressed by DZone contributors are their own.
Comments