1

I have a Spring 5 based webapp where the controller calls this service class and gets the current logged in User information.

Since loggedInUser object has been defined as an instance variable here, will this create a race condition when multiple users try to log into the application and access pages with their credentials ? Should this be a local variable instead of instance variable within the getLoggedInUser() method ?

I was under the impression that Tomcat will create a new thread for every HTTP request and a brand new instance of UserService bean will be created every time a request comes in, irrespective of the user accessing it.

And how can I identify if the bean used by Spring is new instance or singleton? Is there a way to check this at runtime using System.out.println() or any other methodology/tool?

So,

User 1 -> new UserController()    -> new UserService() -> welcome.jsp 
User 1 -> new ProductController() -> new ProductService() -> new UserService() -> product.jsp  

User 2 -> new UserController()    -> new UserService() -> welcome.jsp 
User 2 -> new ProductController() -> new ProductService() -> new UserService() -> product.jsp  

UserService.java

@Service
public class UserService {

    private User loggedInUser;

    public User getLoggedInUser(HttpServletRequest request) {
        if (this.loggedInUser != null) {
            return this.loggedInUser;
        }
        this.loggedInUser = (User) session.getAttribute("loggedInUser");
        return loggedInUser;
    }

}       

2 Answers 2

2

The default scope for Spring beans is singleton Spring Documentation. This means that only one instance of a bean will be created. This can be demonstrated by the following snippet of code.

@RestController
public class TestController {
    @GetMapping("/test")
    public void test() {
        System.out.println(this);
    }
}

Every time /test endpoint is called, the output will be the same, something like this:

com.example.TestController@17870d99
com.example.TestController@17870d99
com.example.TestController@17870d99

Using a different scope, (request scope, for example), running the following code:

@RestController
@Scope(value = WebApplicationContext.SCOPE_SESSION)
public class TestController {
    @GetMapping("/test")
    public void test() {
        System.out.println(this);
    }
}

we will get the following output:

com.example.TestController@3213427f
com.example.TestController@2318434f
com.example.TestController@5e0df012

We can see that the controller is instantiated with every session (in our case with every call to /test end-point).

Now, it is not recommended to use an instance variable in a singleton bean, since this will have unintended consequences (like race conditions, or leaking unauthorized data). If we would want to use an instance variable, we should use the appropriate scope for the bean.

Or just avoid instance variables at all.

Sign up to request clarification or add additional context in comments.

Comments

2

Spring IoC container will create UserService once and will inject the dependency where it is used if this is Singleton which is the default.

You can use VisualVM to take a heap dump and analyze.

And changing loggedInUser to be a ThreadLocal might help.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.