2016-07-20 12 views
1

Ich arbeite an Playframework2.5 mit Play-Slick und damit verbundenen Programmen wie Batch.Erstellen Sie eine Instanz der Klasse, die DI über Playframe Guice unabhängig in Scala tut

aktuelle Projektstruktur ist wie

/rootPlayProject 
    /app 
    /controllers 
    /filters 
    /services 
    ... 
    Modules 
    /core (sub-project - DAOs,services are placed here) 
    /batch (sub-project depends on core) 

Ich verwende Guice DI fast überall Database Access Object (DAO) umfasst. Und Schnittstellen im Kern sind in Module gebunden in core platziert, die am Ende von Module in Root-Projekt vererbt werden.

Core Module (/rootPlayProject/core/CoreModule.scala)

class CoreModule extends AbstractModule { 
    override def configure() = { 
    bind(classOf[FooDAO]).to(classOf[FooDAOImpl]) 
    .... 
    } 
} 

Root-Modul (/rootPlayProject/Modules.scala)

class Module extends CoreModule { 
    override def configure() = { 
    super.configure() 
    bind(classOf[FooService]).to(classOf[FooServiceImpl]) 
    } 
} 

Dies obwohl ziemlich gut als Playframework Anwendung funktioniert, ich möchte Core-Modul für Batch-Programme verwenden und ich würde die Chargen ohne Playframework ausführen möchten.

bisher habe ich versucht, so etwas wie dieses

object BatchA { 
    def main(args: Array[String]) = { 
    val injector = Guice.createInjector(new CoreModule) 
    val foo = injector.getInstance(classOf[FooDAO]) 
    //do something with foo. 
    } 
} 

aber da meine DAO erfordert Dinge schaffen Playframework wie ExecutionContext, play.api.db.slick.DatabaseConfigProvider und @play.db.NamedDatabase, über Code nicht ausgeführt.

Meine Frage ist, wie kann ich diese Dinge binden lassen, ohne Anwendung Builder zu spielen?

Vielen Dank im Voraus.

Antwort

0

GuiceInjectorBuilder tun Sie den Trick.

trait PlayInjector { 
    lazy val injector = new GuiceInjectorBuilder().configure(Configuration.load(Environment.simple(mode = Mode.Dev))) 
    .bindings(new BuiltinModule, new CoreModule, new SlickModule).disable(classOf[Application]).injector 

    def closeInjector = injector.instanceOf[DefaultApplicationLifecycle].stop 
} 

BuiltinModule bindet Basismodule spielen wie ExecutionContext, ExecutionContextExecutor oder ActorSystem. Sie können Ihr eigenes Modul erstellen, um nur Dinge zu binden, die Sie benötigen, indem Sie BuiltinModule verwenden und Klassen deaktivieren, die Sie nicht benötigen, ist einfacher.

wie es

object Foo extends PlayInjector { 
    def main(args: Array[String]) = { 
    val foo = injector.instanceOf[FooDAO] 
    val bar = injector.instanceOf[BarDAO] 
    //do something 
    //when you finish things you want to do 
    closeInjector 
    } 
} 

zu verwenden, da einige Module wie PlaySlick ApplicationLifecycle.addStopHook verwendet Schließvorgang zu handhaben. Es ist sicherer, sie auszuführen, anstatt nur sys.exit()

1

Die Antwort hängt davon ab, ob Sie Play Framework tatsächlich von Ihren DAOs entkoppeln möchten oder nicht.

Option 1: Sie konnte nicht

Ihre Hauptmethode entkoppeln einfach die folgenden Zeilen vorhergehenden Ihre val injector Linie:

val application = new GuiceApplicationBuilder() 
    .in(Environment(new File("."), this.getClass.getClassLoader, Mode.Prod)) 
    .build 
Play.start(application) 

Option 2: Oder

entkoppeln, Sie können injizierbare Klassen bereitstellen, die die ExecutionContext spezifische Umgebung bereitstellen können. Wenn Sie die DatabaseConfigProvider injizieren möchten, müssen Sie weitere Abstraktionen durchführen, um die direkte Abhängigkeit von Play zu entfernen. Die Annotation folgt der Play-spezifischen Implementierung der Abstraktion.


Im Fall meines eigenen Projektes, wo ich dieses Szenario auftreten, entschied ich mich für Option 1, da die Abhängigkeit von Spielen genug einen Aufprall für mich nicht schwer war.

+0

den Fall von 'Option1' zu starten, es bedeutet, dass Anwendung läuft, während ich mache, was ich will, richtig? Wenn es nicht zu schwer ist, bevorzuge ich Letzteres, so dass ich keine Play-Anwendung ausführen muss, um nur einen Batch auszuführen. – suish

+0

In Ihrem Fall könnte Option 2 sinnvoller sein. – doctorless