2016-01-19 8 views
6

Ich möchte die getInstance Methode der Guice Injector Klasse in Play Framework 2.4 verwenden, wie kann ich darauf zugreifen?Zugriff auf Play Framework 2.4 guice Injector in Anwendung?

Ich habe die Guice FactoryModuleBuilder für die Umsetzung einer Fabrik verwendet, die zur Laufzeit eine andere Fabrik zurückgibt! Auf der zweiten Ebene des Zurückgebens einer Fabrik muss ich auf den Play Guice Injector zugreifen, um Objekte manuell unter Verwendung von Reflektion anstelle von @Inject Annotation zu erhalten.

+0

Könnten Sie bitte mehr hier ausführen? Warum müssen Sie auf den Injektor zugreifen? – marcospereira

+0

@marcospereira Ich habe Guice FactoryModuleBuilder für die Implementierung einer Fabrik verwendet, die eine andere Fabrik in der Laufzeit zurückgibt! In der zweiten Ebene der zurückkehrenden Fabrik muss ich auf Play guice Injector zugreifen, um Objekte manuell zu erhalten, indem ich Reflektion anstelle von Inject annotation verwende. –

+0

Ich fragte, weil Sie 'Play.current' vermeiden sollten, da es irgendwann entfernt wird. Vielleicht können Sie den Injektor injizieren? – marcospereira

Antwort

12

Es gibt viele Möglichkeiten. Ich benutze dieses.

Edit: Dies ist für Play Versionen relevant, die < = 2.4 sind:

Play.maybeApplication.map(_.injector.instanceOf[MyProdClass]).getOrElse(new MyDevClass) 

oder

Play.current.injector.instanceOf[MyClass] 

Für Versionen, die> = 2.5 sind:

import play.api.inject.Injector 
import javax.inject.Inject 

class MyService @Inject() (injector: Injector) ={ 
    val myClassInstance = injector.instanceOf[MyClass] 
    //do stuff 
} 
+0

Während technisch korrekt, der erste Ansatz würde zu einer falschen Instanz führen, wenn auf den Injektor statisch zugegriffen wird (in einem produktiven System). Das sollte natürlich nicht passieren, aber der zweite Ansatz wäre zumindest klar. Sie sollten einen anderen Anwendungslader in der Entwicklungsumgebung verwenden, wenn Sie unterschiedliche Bindungen haben möchten. – rethab

+1

Play.current ist veraltet wie alle anderen statischen Accelerators. DI muss anstelle des alten statischen Ansatzes verwendet werden. – Serg

+0

Wie funktioniert der erste Ansatz? Wie wird diese Anwendung erstellt? Ich versuche, Guice Injection in einer Play 2.3-Anwendung einzuführen, wo der Injektor in Global.scala definiert ist? Das funktioniert, aber ich kann keinen vernünftigen Weg finden, um den Injektor ohne die @Inject-Notation an anderer Stelle zu erreichen. – Serendipity

4

Es ist besser injizieren Guice Injector:

@Inject 
private Injector injector; 

Oder können Sie diesen Code für Play-Framework Java-Edition verwenden:

Play.application().injector().instanceOf(YourClass.class); 
5

Mit Play-Framework-2.5.x play.api.Play.current ist veraltet und DI immer bevorzugt werden sollte. Daher richtige Art und Weise Injektor Beispiel des Erhaltens ist durch die Verwendung:

import play.api.inject.Injector 
import javax.inject.Inject 

class SomeClassRequiringInjector @Inject() (injector: Injector) { ... } 

Werke für mich, auch wenn diese Klasse mit DI-Provider tun :)

+1

in meinem Java diese Art der Injektion funktioniert nicht. Irgendeine Idee? –

+1

@SimonFakir in Java sollte man play.inject.Injector einspritzen, weil alles unter play.api. * Für Scala ist. – Serg

+0

@Egregore, ich denke deine Antwort sollte akzeptiert werden! Es wäre auch schön, wenn Sie auch ein Java-Beispiel einschließen, für das play.inject.Injector eingespeist werden muss. – Serg

3

Abgesehen von den anderen Spielen 2.5.x Lösungen gibt es eine Situation sein kann, in dem Sie den Injektor in einem Objekt ohne Injektion zu erhalten möchten. Zum Beispiel, wenn Sie ein Scala-Singleton verwenden, für das @inject wahrscheinlich nicht funktioniert.

In diesem Fall können Sie diese verwenden:

@Singleton 
class GlobalContext @Inject()(injector: Injector) { 
    GlobalContext.injector = injector 
} 

object GlobalContext { 
    private var injector: Injector = null 
} 

Mit einem Guice Modul die Singleton zu eifrig setzen, sonst wird es nicht automatisch initialisiert werden:

// Module.scala 
class Module extends AbstractModule { 
    override def configure() = { 
    // ... 

    // Eager initialize Context singleton 
    bind(classOf[GlobalContext]).asEagerSingleton() 
    } 
} 
I
0

wirklich wie Devabc's solution weil es definitiv einige Szenarien gibt, die sich nicht auf die Konstruktorinjektion stützen können, um den Injektor selbst zu erhalten, stattdessen müssen Sie in Play 2.5.x den veralteten play.api.Play.current.Injector Code verwenden, um den Injektor zu erhalten.

Seine Lösung erstellt einen Verweis auf den Play-Injektor und legt ihn in ein Scala-Objekt, das von jeder Komponente bei Bedarf importiert werden kann. Brillant!

Um es funktionieren zu lassen, muss das Objekt jedoch eine öffentliche Schnittstelle zur Verfügung stellen, um den Injektor zu bekommen, also ist hier mein geänderter Code, um ihn zu reparieren und zu demonstrieren, wie er benutzt werden kann.

import play.api.inject.Injector 
import javax.inject.Inject 

@Singleton 
class GlobalContext @Inject()(playInjector: Injector) { 
    GlobalContext.injectorRef = playInjector 
} 

object GlobalContext { 
    private var injectorRef: Injector = _ 

    def injector: Injector = injectorRef 
} 

Der Initialisierungsteil ist derselbe.

// InjectionModule.scala 
package modules 

class InjectionModule extends AbstractModule { 
    override def configure() = { 
    // ... 

    // Eager initialize Context singleton 
    bind(classOf[GlobalContext]).asEagerSingleton() 
    } 
} 

// application.conf 
play.modules.enabled += "modules.InjectionModule" 

Und der Client-Code ist recht einfach. Für welche Komponente auch der Injektor benötigt wird:

// Import the object GlobalContext 
import GlobalContext.injector 

// ... 
val yourClassInstance = injector.instanceOf[YourClass]