I'm just starting out and I dont think i understand it very well. From what I understand all controllers are created as dependencies the moment the router is created. They then live on until the router dies when the application terminates. If this is the case declaring them as singletons seem redundant.
-
You do not have to declare them as singletons. Where did you read that? – jacks Nov 17 '16 at 08:50
-
Nowhere. But if you look at the controller that come with a play installation they are all annotated as singeltons – user25470 Nov 17 '16 at 09:17
-
Ah I see, I put a larger comment below - it is about statelessness. – jacks Nov 17 '16 at 11:02
-
Controllers used to be Objects in Play Framework and then DI showed up :) – Rémi Lavolée Nov 17 '16 at 13:53
2 Answers
To get rid of global state (which goes against the idea of a stateless design) Play introduced DI (I think around v2.4) and in v2.5 it now uses an injected router by default. Google Guice is the default DI framework packaged by Play (you can use others but Guice is the default).
Now (in general) Guice takes the view that creating new instances of a Controller is faster, and more thread safe than using a singleton - see the Guice docs for more.
If you have a need to restrict instances of a controller to only 1 then you can mark it a singleton BUT you have to make it Thread-safe since it will then be shared between threads.
I think the Activator templates could do with a bit more documentation around them to explain why they seem to generate @Singleton
controllers when they do not seem to be needed since it is confusing. HomeController
(in the Play-Scala seed) for example is confusingly declared @Singleton
when it exhibits no case for it.
In general, it is probably best to not use @Singleton
unless you have a fair understanding of immutability and thread-safety. If you think you have a use case for Singleton though just make sure you are protecting any shared state.
In a nutshell, don't use @Singleton
.
-
-
I guess I am still a bit confused. I still cany see anu time where more the one instance would be created. So the singleton notation still seems redundant. Also I am under the impression that all requests are handled by the same thread so it doesn't matter if it is stateless or not – user25470 Nov 17 '16 at 17:44
-
@user25470 1 thread per request, otherwise all your requests have to queue up waiting to take their turn on 1 thread which would mean your App is very slow. You may have read in the docs that Actions are meant to be Non-blocking - this means that you should never do anything in a controller action that may cause it to get context switched (eg. I/O) - this is because the default thread pool for Play is 1 thread per core on the host. So a thread gets assigned a request, executes the action quickly (non-blocking) and gets returned to pool quickly to handle the next. – jacks Nov 17 '16 at 18:16
If you have a controller that is instantiated by the router (ie. the default), then they are implicitly singletons, because the router exists only once. However if you inject the controller somewhere else, you'd still get a new instance unless it is marked as singleton.
Source: https://github.com/playframework/playframework/issues/4508#issuecomment-127820190

- 7,170
- 29
- 46
-
Can you give me an example of when you would inject a controller elsewhere? – user25470 Nov 17 '16 at 07:39
-
1No. I think that's bad practice. If you want to share functionality you should create a business service or some other helper class. I think the point about injecting a controller elsewhere is rather technical to ephasize that the controllers aren't *really* singletons. – rethab Nov 17 '16 at 07:57