2016-04-06 8 views
14

Ich habe eine Konfigurationsdatei servers.conf in meinem conf/ Verzeichnis, das von meinem ServerController gelesen wird, wenn die Route /servers getroffen wird. Dies ist nicht performant, da bei jedem weiteren Treffer ein erneutes Lesen der Konfigurationsdatei erforderlich ist, wenn sich die Datei nicht ändert. Wenn es Probleme mit der Konfigurationsdatei gibt, kann ich den Benutzer so schnell wie möglich informieren, anstatt eine Ausnahme bei einem Seitentreffer auszulösen.Wie führe ich eine Aktion beim Serverstart im Scala Play Framework durch?

Zur Zeit habe ich dies in meinem ServerController.scala:

case class Server(ip: String, port: String) 

/** 
    * This controller creates an `Action` to handle HTTP requests to the 
    * application's server page. 
    */ 
@Singleton 
class ServerController @Inject() extends Controller { 

    /** 
    * Create an Action to render an HTML page with a the list of servers. 
    * The configuration in the `routes` file means that this method 
    * will be called when the application receives a `GET` request with 
    * a path of `/servers`. 
    */ 
    def index = Action { 

    val serverList = ConfigFactory.load().getConfigList("servers") 
    val servers: List[Server] = serverList match { 
     case null => Nil 
     case _ => serverList map { s => 
     Server(s.getString("ip"), s.getString("port")) 
     } filter { s => 
     s.ip != null && s.port != null 
     }.toList 
    } 

    Ok(views.html.servers(servers)) 
    } 
} 

Mein Ziel ist der Server die Konfiguration haben Datei beim Start und übergeben Sie die Liste der Server an die ServerController lesen, wenn die Route getroffen wird, wenn es keine ist Probleme beim Lesen in der Konfigurationsdatei. Wenn es Probleme gibt, möchte ich sofort eine Ausnahme auslösen.

Ich kann jedoch keinen Einstiegspunkt für meine Anwendung finden, daher weiß ich nicht, wie ich beim Start Aktionen ausführen soll.

Weiß jemand, wie man das macht? Ich benutze Play 2.5.x.

+0

Welche Version von Play verwenden Sie? – Anton

+0

@Anton Entschuldigung. Bearbeitete die Frage. – erip

+0

Haben Sie darüber nachgedacht, den gesamten Codeblock außerhalb der Indexfunktion zu platzieren? (Es wird ausgeführt, wenn der Controller nur einmal gestartet wird, d. H. Eine HTTP-Anfrage an diesen Controller) – dlite922

Antwort

15

Wenn Sie die neueste Version von Play verwenden, sucht sie beim Start nach einer beliebigen Klasse namens Module, die sich im Root-Paket befindet (dh es gibt keine package Definition am Anfang der Datei). Hier ist ein Beispiel aus der neuesten Activator-Vorlage für Play 2.5.x, die ich für die Demonstration von laufendem Code beim Start und Herunterfahren der Anwendung geändert habe:

In services/Say.scala wäre dies ein einfacher Service zu sagen "Hallo!" beim Start und "Auf Wiedersehen!" wenn die Anwendung heruntergefahren:

package services 

import javax.inject._ 
import play.api.inject.ApplicationLifecycle 
import scala.concurrent.Future 

trait Say { 
    def hello(): Unit 
    def goodbye(): Unit 
} 

@Singleton 
class SayImpl @Inject() (appLifecycle: ApplicationLifecycle) extends Say { 
    override def hello(): Unit = println("Hello!") 
    override def goodbye(): Unit = println("Goodbye!") 

    // You can do this, or just explicitly call `hello()` at the end 
    def start(): Unit = hello() 

    // When the application starts, register a stop hook with the 
    // ApplicationLifecycle object. The code inside the stop hook will 
    // be run when the application stops. 
    appLifecycle.addStopHook {() => 
     goodbye() 
     Future.successful(()) 
    } 

    // Called when this singleton is constructed (could be replaced by `hello()`) 
    start() 
} 

In Module.scala,

import com.google.inject.AbstractModule 
import services._ 

/** 
* This class is a Guice module that tells Guice how to bind several 
* different types. This Guice module is created when the Play 
* application starts. 

* Play will automatically use any class called `Module` that is in 
* the root package. You can create modules in other locations by 
* adding `play.modules.enabled` settings to the `application.conf` 
* configuration file. 
*/ 
class Module extends AbstractModule { 

    override def configure() = { 
    // We bind the implementation to the interface (trait) as an eager singleton, 
    // which means it is bound immediately when the application starts. 
    bind(classOf[Say]).to(classOf[SayImpl]).asEagerSingleton() 
    } 
} 

Einige weitere Ressourcen können für Sie nützlich sind the Scala dependency injection (DI) documentation und the Guice documentation. Guice ist das Standard-DI-Framework, das von Play verwendet wird.

+0

Nice. Das scheint ziemlich nahe zu sein, was ich will. Weißt du, in welchem ​​Verzeichnis 'root' leben soll? – erip

+1

Nun, es ist kein Verzeichnis namens "root". Es ist nur eine Datei, die sich im root-Paket befindet, das heißt, sie hat keine "package" -Deklaration am Anfang. Alternativ können Sie das Modul irgendwo anders definieren, zB in einem 'modules'-Verzeichnis, und es in Ihrer' application.conf' so aktivieren: 'play.modules.enabled + =" com.example.modules "', where 'com.example.modules' sollte das Paket sein, zu dem Ihr Modul gehört. – Eric

+0

Richtig, also wird mein 'root' Paket standardmäßig in' app/'leben? Das heißt, wenn ich "Say.scala" in "service /" und "Module.scala" in "app /' paketiert als "root" lege, sollte es funktionieren? – erip