Как выполнить действие при запуске сервера в 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
определение в верхней части файла). Вот пример, взятый из последнего шаблона 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()
}
}
Некоторыми дополнительными ресурсами, которые вы можете найти полезными, являются документация по внедрению зависимостей Scala и документация Guice. Guice - это стандартная структура DI, используемая Play.