2016-04-06 2 views
14

У меня есть файл конфигурации servers.conf в моем каталоге conf/, который считывается моим ServerController всякий раз, когда удаляется маршрут /servers. Это не работает, потому что для повторного чтения файла конфигурации требуется повторный просмотр файла с последующим ударом, когда файл не изменится. Кроме того, если есть проблемы с конфигурационным файлом, я могу сказать пользователю ASAP, а не вызывать исключение на странице.Как выполнить действие при запуске сервера в Scala Play Framework?

В настоящее время у меня есть это в моем 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)) 
    } 
} 

Моя цель не состоит в том, что сервер прочитать конфигурационный файл при запуске и передать список серверов на ServerController, когда маршрут попал, если нет чтение проблем в файле конфигурации. Если есть проблемы, я хочу, чтобы исключение было немедленно отправлено.

Хотя я не могу найти точку входа для своего приложения, поэтому я не знаю, как выполнять действия при запуске.

Кто-нибудь знает, как это сделать? Я использую Play 2.5.x.

+0

Какую версию вы используете? – Anton

+0

@ Антон Извините. Отредактировал вопрос. – erip

+0

Считаете ли вы, что весь блок кода находится за пределами функции индекса? (Он запускается, когда контроллер запускается только один раз, т. Е. Любой HTTP-запрос, сделанный для этого контроллера) – dlite922

ответ

15

Если вы используете последнюю версию Play, она запускается при запуске для любого класса с именем Module, который находится в корневом пакете (то есть в верхней части файла нет определения package). Вот пример, взятый из последнего шаблона Activator для Play 2.5.x, который я изменил для демонстрации кода запуска при запуске и завершении приложения:

В services/Say.scala это было бы простой услугой, чтобы сказать «Привет!». при запуске и «До свидания!» когда приложение завершает работу:

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

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

Некоторые дополнительные ресурсы, которые могут оказаться полезными являются the Scala dependency injection (DI) documentation и the Guice documentation. Guice - это каркас DI по умолчанию, используемый Play.

+0

Nice. Это похоже на то, что я хочу. Знаете ли вы, в каком каталоге должен жить «root»? – erip

+1

Ну, это не каталог с именем 'root'. Это всего лишь файл, который находится в корневом пакете, т. Е. Он не имеет декларации 'package' наверху. В качестве альтернативы вы можете определить модуль в другом месте, например, в директории 'modules', и включить его в свой' application.conf' так: 'play.modules.enabled + =" com.example.modules "', где 'com.example.modules' должен быть пакетом, к которому принадлежит ваш модуль. – Eric

+0

Правильно, поэтому мой пакет 'root', как ожидается, будет жить в' app/'по умолчанию? То есть, если я помещаю 'Say.scala' в' service/'и' Module.scala' живет в 'app /', упакованном как 'root', он должен работать? – erip

Смежные вопросы