SpringBoot控制器使用final修饰Service对象是否违反无状态最佳实践?
Good question! Let's clarify this step by step, since it's a common point of confusion when working with Spring Boot controllers.
First, let's define what makes a controller stateful (and why that's bad):
A stateful controller holds mutable data that changes between requests — things like user-specific session data, request counters, or temporary variables tied to a single request/response cycle that persist across different requests. Since Spring controllers are singletons by default (one instance shared across all requests), any mutable state would cause cross-request contamination, which is a big no-no.
Now, looking at your code:
@RestController @RequestMapping(value = "/users") public class UserController { final UserService userService; public UserController(UserService userService) { this.userService = userService; } }
This is not stateful — in fact, it's a recommended best practice. Here's why:
- The
userServicefield is markedfinal, meaning it can only be assigned once (in the constructor) and will never change for the lifetime of the controller instance. - Your
UserService(if designed correctly, as most Spring services are) should be a stateless singleton bean. It doesn't hold request-specific data; it delegates to repositories or other stateless components. - Since the controller's only field is an immutable reference to a stateless service, there's no mutable state being shared across requests. The controller instance remains safe to reuse for every incoming request.
To contrast, here's an example of a stateful controller that violates best practices:
@RestController @RequestMapping("/users") public class BadUserController { // This mutable field will be shared across all requests! private int requestCount = 0; private final UserService userService; public BadUserController(UserService userService) { this.userService = userService; } @GetMapping public List<User> getUsers() { requestCount++; // This value will increment for every request, causing cross-request interference return userService.getAllUsers(); } }
In short: Using final for injected service dependencies is not just safe — it's encouraged. It ensures your dependencies can't be accidentally modified, makes unit testing easier (you can mock the service cleanly), and keeps your controller stateless as required by Spring's best practices.
内容的提问来源于stack exchange,提问作者Tim Hudson

