48

Are all controllers in Spring-MVC singletons and are shared among different sessions and requests?

If so, I assume that a class-variable like

public String name;

would be the same for all requests and sessions? So that if User X makes a request and name is being set to Paul, User Z also has Paul as attribute?

In my case I do NOT want that behaviour but wondered if there is a more easier, or more cleaner OOP-way to have session/request-variables then session.getAttribute()/request.getAttribute()

Gundon
  • 2,081
  • 6
  • 28
  • 46

2 Answers2

73

To answer your first question: yes, Spring MVC controllers are singletons by default. An object field will be shared and visible for all requests and all sessions forever.

However without any synchronization you might run into all sorts of concurrency issues (race conditions, visibility). Thus your field should have volatile (and private, by the way) modifier to avoid visibility issues.

Back to your main question: in Spring you can use request- (see 4.5.4.2 Request scope) and session-scoped (see: 4.5.4.3 Session scope) beans. You can inject them to controllers and any other beans (even singletons!), but Spring makes sure each request/session has an independent instance.

Only thing to remember when injecting request- and session-scoped beans into singletons is to wrap them in scoped proxy (example taken from 4.5.4.5 Scoped beans as dependencies):

<!-- an HTTP Session-scoped bean exposed as a proxy -->
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">

    <!-- instructs the container to proxy the surrounding bean -->
    <aop:scoped-proxy/>
</bean>
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • +1 Note: "even singletons!" requires auto-proxying the injected beans – Sean Patrick Floyd Jun 21 '12 at 14:17
  • @SeanPatrickFloyd: yes, this is so important that I added an example from Spring docs, thanks! – Tomasz Nurkiewicz Jun 21 '12 at 14:22
  • 2
    From https://stackoverflow.com/questions/4503606/annotation-equivalent-of-aopscoped-proxy, use @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) to configure aop:scoped-proxy using annotations. – downeyt Aug 02 '18 at 21:39
  • We are missing one of the basis of spring: controllers are beans, hence they should not have status (beyond the injected dependencies) unless those beans are meant to store data. To avoid data sharing among requests I have seen @scope Session or request in beans supporting forms in jsf (properly configured to use spring beans). Controllers are not beans meant to carry data but classes that support view logic, hence they should be stateless and consequently singleton – Jose Luis Apr 14 '21 at 16:42
13

Yes, controllers in Spring-MVC are singletons. Between multiple requests your class variable get shared and might result into ambiguity. You can use @Scope("request") annotation above your controller to avoid such ambiguity.

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
Ankit Pandoh
  • 548
  • 5
  • 14
  • 1
    Some example with explanation would be great. – Nilambar Sharma Jun 25 '15 at 04:07
  • @Controller public class TestClass { private String name; @RequestMapping("/") public String displayName(){ if(this.name != null){ this.name = "ABC"; }else{ this.name = "XYZ"; } SystemOut.println(name); return this.name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } – Ankit Pandoh Jun 25 '15 at 05:21
  • In Continuation to my previous edit.. For first request it will print XYZ but for another parallel request it will print ABC but ideally if two users are issuing two different request they both should see XYZ. By making @Scope("request") will give us the desired result. Please let me know if I went wrong somewhere – Ankit Pandoh Jun 25 '15 at 05:22
  • 1
    Yes that works perfectly. What does that @Scope("request") annotation does actually ? Does that create a new controller object for every request? What if two request reach the same requestMapping at exactly same time? – New Bee Jun 15 '16 at 08:25
  • 1
    @New Bee, yes it will create new instance for each http request and if the 2 requests comes at a time then for both it will create separate instance and handle the request. – Atul Sep 05 '19 at 09:15