Как выполнить действие при запуске сервера в Scala Play Framework?
У меня есть конфигурационный файл servers.conf
в моем каталоге conf/
, который считывается моим ServerController всякий раз, когда маршрут /servers
попадает. Это не является эффективным, так как требует повторного чтения файла конфигурации при каждом последующем попадании, когда файл не изменяется. Далее, если есть проблемы с файлом конфигурации, я могу сказать пользователю как можно скорее, а не выбрасывать исключение на странице хита.
В настоящее время у меня есть это в моем 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.
1 ответ:
Если вы используете последнюю версию Play, он ищет при запуске любой класс под названием
Module
, который находится в корневом пакете (то есть в верхней части файла нет определенияpackage
). Вот пример, взятый из последнего шаблона активатора для 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() }
В Модуле.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() } }
Некоторые дополнительные ресурсы, которые вы можете найти полезными, являются документацией Scala dependency injection (DI) и документацией Guice. Guice-это платформа DI по умолчанию, используемая Play.