2016-04-06 32 views
14

Ho un file di configurazione servers.conf nella mia directory conf/ che viene letto dal mio ServerController ogni volta che viene colpito il percorso /servers. Questo non è performante perché richiede una rilettura del file di configurazione su ogni colpo successivo quando il file non cambia. Inoltre, se ci sono problemi con il file di configurazione, posso dire all'utente ASAP piuttosto che lanciare un'eccezione su un colpo di pagina.Come si esegue un'azione all'avvio del server in Scala Play Framework?

Attualmente ho questo nel mio 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)) 
    } 
} 

Il mio obiettivo è quello di avere il server leggere il file di configurazione all'avvio e passare l'elenco dei server al ServerController durante il percorso viene colpito, se non ci sono problemi di lettura nel file di configurazione. Se ci sono problemi, voglio che venga lanciata un'eccezione immediatamente.

Tuttavia, non riesco a trovare un punto di ingresso per la mia applicazione, quindi non so come eseguire le azioni all'avvio.

Qualcuno sa come fare? Sto usando Play 2.5.x.

+0

Quale versione di Play stai usando? – Anton

+0

@ Anton Sorry. Modificato la domanda. – erip

+0

Hai considerato di mettere l'intero blocco di codice al di fuori della funzione indice? (Esegue quando il controller viene avviato una sola volta, ad esempio qualsiasi richiesta HTTP inoltrata a quel controller) – dlite922

risposta

15

Se si utilizza l'ultima versione di Play, viene visualizzato all'avvio per qualsiasi classe denominata Module presente nel pacchetto radice (ovvero, non esiste una definizione package nella parte superiore del file). Ecco un esempio tratto dall'ultimo modello Activator per Play 2.5.x, che ho modificato per la dimostrazione del codice in esecuzione all'avvio e all'arresto dell'applicazione:

In services/Say.scala, questo sarebbe un servizio semplice per dire "Ciao!" all'avvio e "Arrivederci!" quando l'applicazione viene chiusa:

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() 
    } 
} 

Alcuni ulteriori risorse si possono trovare utili sono the Scala dependency injection (DI) documentation e the Guice documentation. Guice è il framework DI predefinito utilizzato da Play.

+0

Nice. Questo sembra essere abbastanza vicino a quello che voglio. Sai in quale directory 'root' dovrebbe vivere? – erip

+1

Beh, non è una directory chiamata 'root'. È solo un file che risiede nel pacchetto root, vale a dire che non ha una dichiarazione 'package' in alto. In alternativa, puoi definire il modulo da qualche altra parte, ad esempio in una directory 'modules', e abilitarlo nel tuo' application.conf' in questo modo: 'play.modules.enabled + =" com.example.modules "', dove 'com.example.modules' dovrebbe essere il pacchetto a cui appartiene il tuo modulo. – Eric

+0

Bene, quindi il mio pacchetto 'root' dovrebbe vivere in' app/'di default? Cioè, se metto 'Say.scala' in' service/'e' Module.scala' vive in 'app /' impacchettato come 'root', dovrebbe funzionare? – erip