Why Spring Boot Controllers Are Singleton by Default and How to Avoid Thread Safety Issues

This article explains that Spring Boot controllers are singleton by default, why that makes them unsafe when using non‑static fields, demonstrates the problem with sample code, and provides practical solutions such as using prototype scope or ThreadLocal variables.

Programmer DD
Programmer DD
Programmer DD
Why Spring Boot Controllers Are Singleton by Default and How to Avoid Thread Safety Issues

Spring MVC controllers are singleton by default, so defining non‑static member variables can cause data logic confusion and thread‑safety problems.

Below is a simple demonstration.

package com.riemann.springbootdemo.controller;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author riemann
 * @date 2019/07/29 22:56
 */
@Controller
public class ScopeTestController {

    private int num = 0;

    @RequestMapping("/testScope")
    public void testScope() {
        System.out.println(++num);
    }

    @RequestMapping("/testScope2")
    public void testScope2() {
        System.out.println(++num);
    }
}

When accessing http://localhost:8080/testScope the output is 1; then accessing http://localhost:8080/testScope2 yields 2. The different values show the controller is not thread‑safe.

Adding @Scope("prototype") to make the controller prototype:

package com.riemann.springbootdemo.controller;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author riemann
 * @date 2019/07/29 22:56
 */
@Controller
@Scope("prototype")
public class ScopeTestController {

    private int num = 0;

    @RequestMapping("/testScope")
    public void testScope() {
        System.out.println(++num);
    }

    @RequestMapping("/testScope2")
    public void testScope2() {
        System.out.println(++num);
    }
}

Now both URLs return 1, confirming each request gets a new instance.

Conclusion: singleton controllers are unsafe because their fields are shared across requests.

Solution

Do not define member variables in a controller.

If a non‑static field is necessary, annotate the controller with @Scope("prototype") to use prototype scope.

Alternatively, use ThreadLocal variables inside the controller.

Additional Information

Spring bean scopes include:

singleton : a single instance per Spring container (eagerly created unless lazy‑init is used).

prototype : a new instance each time getBean is called; Spring does not manage the lifecycle after creation.

request : a new instance for each HTTP request in a web application.

session : a new instance for each HTTP session.

global session : a global web scope similar to the servlet application context.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

thread safetyControllerSingletonprototypespring-bootBean Scope
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.