Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why use @Singleton over Scala's object in Play Framework?

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?

like image 959
Rhys Bradbury Avatar asked May 17 '16 17:05

Rhys Bradbury


People also ask

What does @singleton annotation do?

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.

Why do we use singleton object in Scala?

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.

What is inject in Scala?

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.

What is a Scala object?

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.


1 Answers

Is injection the preferred way? Generally yes

A couple advantages of using dependency injection:

  1. Decouple controller from the concrete implementation of Counter.
    • If you were to use an object, you would have to change your controller to point to the different implementation. EG Counter2.nextCount().toString
  2. You can vary the implementation during testing using Guice custom bindings
    • Lets say that inside of 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.

like image 114
nattyddubbs Avatar answered Sep 22 '22 09:09

nattyddubbs