Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is each Play framework web request handled with a new dependency injected controller instance, but then what about static controller methods?

My questions are about the lifecycle of controllers in the Play framework for Java, if the controllers are stateful instances or stateless with static methods, and how to use dependency injection in the controller code.

Is each web request handled by a new instance of a Play controller class, i.e. can a controller store state in fields such as services injected into the controller constructor? (where in the documentation is it explained?)

Has the Play framework changed since earlier versions (and if so, at what version?) regarding if controllers are stateful instances or stateless controllers with static methods?

Where can you see code examples about how the framework injects services into a controller instance when stateful controller is used and example of how to inject services into a static controller method?

Regarding the latter, i.e. injection into a static method I suppose that would either have to be a parameter to the method which the frameworks will add, or if not possible you maybe instead will have to use a service locator from within the method e.g. instantiate a Guice module class and then use "injector.getInstance" from within the static controller method.

This subject is touched in the section "Dependency injecting controllers" at the following page:

https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection

However, it does not show with code how to actually inject services into a controller instance (but probably the same way as other "components" i.e. with @Inject annotation) and certainly it does not currently show how to use DI with a static controller method.

I am confused about these things because I have not found documentation being clear about my questions, and I have also read in a Play book (from 2013) that the controller methods should be programmed as stateless and the controller methods should be static.

However, when now using activator for generating a Play application for Java with the latest Play version (2.4.6) I can see that the generated Controller method (Application.index) is NOT static. Also, at the following documentation page, the controller method is NOT static: https://www.playframework.com/documentation/2.4.x/JavaActions

This is confusing, and since it is VERY fundamental to understand whether or not each request is handled by a Controller instance or not (i.e. if state can be used) I think this should be better documented at the page about Controller/Actions than the current documentation (the above linked page) which is not explaining it.

The documentation about dependency injection touches the subject about static and non-static methods at the section "Dependency injecting controllers" mentioning "static routes generator" but I think it should be better explained including code examples.

If someone in the Play team is reading this question, then please add some information to the above linked pages, for example please do mention (if my understanding is correct) that in previous versions of Play the controller methods were static and for those versions you should never store state in fields, but in later versions (beginning from version x?) each request is handled by an instance of a controller and can therefore use state (e.g. constructor parameters injected by the framework).

Please also provide code examples about injection used with static controller methods and injection into stateful controller instances with one instance per request.

The section "Component lifecycle" in the dependency injection page only mentions "components" but I think it should also be explicit about the controller lifecycle and its injection, since it is such a fundamental and important knowledge to communicate clearly to all developers to avoid bugs caused by misunderstandings about being stateful or not.

like image 514
Pelle Avatar asked Jan 18 '16 20:01

Pelle


People also ask

What is inject in play framework?

Dependency injection is a widely used design pattern that helps to separate your components' behaviour from dependency resolution. Components declare their dependencies, usually as constructor parameters, and a dependency injection framework helps you wire together those components so you don't have to do so manually.

What is MVC in play framework?

A play application follows the MVC architectural pattern applied to the Web architecture. This pattern splits the application into separate layers: the Presentation layer and the Model layer. The Presentation layer is further split into a View and a Controller layer.

Why play framework is used?

Play Framework makes it easy to build web applications with Java & Scala. Play is based on a lightweight, stateless, web-friendly architecture. Built on Akka, Play provides predictable and minimal resource consumption (CPU, memory, threads) for highly-scalable applications.

What is dependency injection stack overflow?

Dependency injection is a pattern to allow your application to inject objects on the fly to classes that need them, without forcing those classes to be responsible for those objects. It allows your code to be more loosely coupled, and Entity Framework Core plugs in to this same system of services.


1 Answers

Is each web request handled by a new instance of a Play controller class, i.e. can a controller store state in fields such as services injected into the controller constructor? (where in the documentation is it explained?)

As far as I can tell, controllers are by default singleton objects. This is not clearly documented, but it is implied that controller instances are reused. See the migration guide for Playframework 2.4:

The injected routes generator also supports the @ operator on routes, but it has a slightly different meaning (since everything is injected), if you prefix a controller with @, instead of that controller being directly injected, a JSR 330 Provider for that controller will be injected. This can be used, for example, to eliminate circular dependency issues, or if you want a new action instantiated per request.

Also, check this commend made by James Roper (Play core committer) about if controllers are singleton or not:

Not really - if using Guice, each time the controller is injected into something, a new instance will be created by default. That said, the router is a singleton, and so by association, the controllers it invokes are singleton. But if you inject a controller somewhere else, it will be instantiated newly for that component.

This suggests that the default is to reuse controller instances when responding to requests and, if you want a new action per request, you need to use the syntax described in the migration guide. But... since I'm more inclined to prove and try things instead of just believe, I've created a simple controller to check that statement:

package controllers

import play.api._
import play.api.mvc._

class Application extends Controller {

  def index = Action {
    println(this)
    Ok(views.html.index("Your new application is ready."))
  }

}

Doing multiple requests to this action prints the same object identity for all the requests made. But, if I use the @ operator on my routes, I start to get different identities for each request. So, yes, controllers are (kind of) singletons by default.

Has the Play framework changed since earlier versions (and if so, at what version?) regarding if controllers are stateful instances or stateless controllers with static methods?

By default, Play had always advocated stateless controllers, as you can see at the project homepage:

Play is based on a lightweight, stateless, web-friendly architecture.

That had not changed. So, you should not use controllers' fields/properties to keep data that changes over time/requests. Instead, just use controllers' fields/properties to keep a reference to other components/services that are also stateless.

Where can you see code examples about how the framework injects services into a controller instance when stateful controller is used and example of how to inject services into a static controller method?

Regarding code examples, Lightbend templates repository is the place to go. Here are some examples that use dependency injection at the controllers level:

  1. https://github.com/adrianhurt/play-api-rest-seed
  2. https://github.com/knoldus/playing-reactive-mongo
  3. https://github.com/KyleU/boilerplay

Dependency Injection with static methods is not supported, and that is why Playframework stills offers old apis to use with static methods. The rule of thumb here is: choose between DI and static methods. Trying to use both will just bring complexity to your application.

like image 90
marcospereira Avatar answered Sep 30 '22 19:09

marcospereira