Warum mit @Singleton über Scala-Objekt im Play Framework?
Ich habe mit Spielen! Rahmen für Scala seit fast einem Jahr jetzt. Ich bin derzeit mit version 2.5.x.
Ich bin mir bewusst, die evolution des controllers in Spielen und wie die Entwickler waren gezwungen, Weg von statischen object
Routen.
Ich bin mir auch bewusst, Guice Verwendung in spielen.
Wenn Sie den download Aktivator und ausführen:
activator new my-test-app play-scala
Aktivator erzeugt ein template Projekt für Sie.
Meine Frage ist, speziell rund um diese - Datei der Vorlage.
mein-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()
}
Können Sie auch sehen, die Nutzung im diese Datei:
mein-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) }
}
Das bedeutet, dass jeder controller, hat der Konstruktor der @Inject() (counter: Counter)
erhalten die gleiche Instanz von Counter
.
Also meine Frage ist:
Warum @Singleton
und dann @Inject
ihn in einen controller, wenn für dieses Beispiel könnte man einfach ein Scala-Objekt?
Seine viel weniger code.
Beispiel:
mein-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()
}
Verwenden Sie es wie so:
mein-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) }
}
Was ist der Unterschied? Ist die Injektion bevorzugt, und warum?
- Es wahrscheinlich egal, wenn Sie nicht brauchen, um Parameter an den controller. Aber wenn Sie das tun, dann muss es eine Klasse sein, die für guice zu instanziieren und injizieren der Abhängigkeiten.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Injektion ist die bevorzugte Art und Weise? In der Regel ja
Ein paar Vorteile der Verwendung von dependency injection:
Counter
.object
müssten Sie ändern, um Ihre controller zu zeigen, um die unterschiedliche Umsetzung. ZBCounter2.nextCount().toString
Counter
du machst einenWS
nennen. Dies könnte dazu führen, dass einige Schwierigkeiten beim unit-testing. Wenn Sie der Verwendung von dependency injection mit Guice, können Sie überschreiben die Bindung zwischenCounter
undAtomicCounter
auf eine offline-version vonCounter
dass Sie geschrieben haben speziell für Ihre tests. Sehen hier für weitere Informationen über die Verwendung von Guice für die Play-tests.Siehe auch die Motivationen, dass Spiel hatte für die Migration zu DI.
Ich sage im Allgemeinen, weil ich gesehen habe, dependency injection, schief gehen mit Spring und andere Java-frameworks. Ich würde sagen, Sie sollten Ihr eigenes Urteil, aber irren auf der Seite mit DI zu Spielen.
Vielleicht, weil Scala singleton-Objekt kann nicht über Parameter? Zum Beispiel, wenn Sie eine service-Klasse, die eine DAO injiziert, und Sie wollen für die Nutzung des service in den controller, Sie haben, um es zu injizieren. Am einfachsten(IMO) ist DI mit Guice... Auch Sie können Ihre Abhängigkeiten in einem Ort(Modul) etc...
Ich bin mir nicht sicher, ob ich verstehe Ihre Frage, aber die Injektion ist bevorzugt, weil:
Kurz zu sprechen: D von FESTEN Grundsätzen: "Abstraktionen Abhängen. Verlassen Sie sich nicht auf Konkretionen".