I have been using Play! Framework for Scala for nearly a year now. I am currently using version 2.5.x.
I am aware of the evolution of controllers in Play and how developers have been forced away from static object
routes.
I am also aware of the Guice usage in play.
If you download activator and run:
activator new my-test-app play-scala
Activator will produce a template project for you. My question is specifically around this file of that template.
my-test-app/app/services/Counter.scala
package services import java.util.concurrent.atomic.AtomicInteger import javax.inject._ /** * This trait demonstrates how to create a component that is injected * into a controller. The trait represents a counter that returns a * incremented number each time it is called. */ trait Counter { def nextCount(): Int } /** * This class is a concrete implementation of the [[Counter]] trait. * It is configured for Guice dependency injection in the [[Module]] * class. * * This class has a `Singleton` annotation because we need to make * sure we only use one counter per application. Without this * annotation we would get a new instance every time a [[Counter]] is * injected. */ @Singleton class AtomicCounter extends Counter { private val atomicCounter = new AtomicInteger() override def nextCount(): Int = atomicCounter.getAndIncrement() }
You can also see its usage in this file:
my-test-app/app/controllers/CountController.scala
package controllers import javax.inject._ import play.api._ import play.api.mvc._ import services.Counter /** * This controller demonstrates how to use dependency injection to * bind a component into a controller class. The class creates an * `Action` that shows an incrementing count to users. The [[Counter]] * object is injected by the Guice dependency injection system. */ @Singleton class CountController @Inject() (counter: Counter) extends Controller { /** * Create an action that responds with the [[Counter]]'s current * count. The result is plain text. This `Action` is mapped to * `GET /count` requests by an entry in the `routes` config file. */ def count = Action { Ok(counter.nextCount().toString) } }
This means every controller which has the constructor of @Inject() (counter: Counter)
will receive the same instance of Counter
.
So my question is:
Why use @Singleton
and then @Inject
it into a controller, when for this example you could just use a Scala object?
Its a lot less code.
Example:
my-test-app/app/services/Counter.scala
package services trait ACounter { def nextCount: Int } object Counter with ACounter { private val atomicCounter = new AtomicInteger() def nextCount(): Int = atomicCounter.getAndIncrement() }
Use it like so:
my-test-app/app/controllers/CountController.scala
package controllers import javax.inject._ import play.api._ import play.api.mvc._ import services.{Counter, ACounter} /** * This controller demonstrates how to use dependency injection to * bind a component into a controller class. The class creates an * `Action` that shows an incrementing count to users. The [[Counter]] * object is injected by the Guice dependency injection system. */ @Singleton class CountController extends Controller { //depend on abstractions val counter: ACounter = Counter def count = Action { Ok(counter.nextCount().toString) } }
What is the difference? Is injection the preferred, and why?
With CDI (Contexts and Dependency Injection), we can easily create singletons using the @Singleton annotation. This annotation is a part of the javax. inject package. It instructs the container to instantiate the singleton once and passes its reference to other objects during the injection.
Instead of static keyword Scala has singleton object. A Singleton object is an object which defines a single object of a class. A singleton object provides an entry point to your program execution. If you do not create a singleton object in your program, then your code compile successfully but does not give output.
Dependency injection is a widely used design pattern that helps separate your components' behaviour from dependency resolution. Play supports both runtime dependency injection based on JSR 330 (described in this page) and compile time dependency injection in Scala.
In Scala, an object is a named instance with members such as fields and methods. An object and a class that have the same name and which are defined in the same source file are known as companions. Companions has special access control properties, which is covered under Scala/Access modifiers.
Is injection the preferred way? Generally yes
A couple advantages of using dependency injection:
Counter
. object
, you would have to change your controller to point to the different implementation. EG Counter2.nextCount().toString
Counter
you are doing a WS
call. This could cause some difficulty unit testing. If you are using dependency injection with Guice, you can override the binding between Counter
and AtomicCounter
to point to an offline version of Counter
that you have written specifically for your tests. See here for more info on using Guice for Play tests.Also see the motivations that Play had for migrating to DI.
I say generally because I've seen dependency injection go horribly wrong using Spring and other Java frameworks. I'd say you should use your own judgement but err on the side of using DI for Play.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With