简体   繁体   English

如何在Scala Play Framework中对服务器启动执行操作?

[英]How do I perform an action on server startup in the Scala Play Framework?

I have a config file servers.conf in my conf/ directory that is read by my ServerController whenever the route /servers is hit. 我的conf/目录中有一个配置文件servers.conf ,只要路由/servers被命中,我的ServerController就会读取它。 This isn't performant because it requires a re-read of the configuration file on each successive hit when the file won't change. 这不具备性能,因为当文件不会更改时,它需要在每次连续命中时重新读取配置文件。 Further if there are problems with the config file, I can tell the user ASAP rather than throw an exception on a page hit. 此外,如果配置文件有问题,我可以尽快告诉用户,而不是在页面命中时抛出异常。

Currently I have this in my ServerController.scala : 目前我在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))
  }
}

My goal is to have the server read the config file at startup and pass the list of servers to the ServerController when the route is hit if there are no problems reading in the config file. 我的目标是让服务器在启动时读取配置文件,并在路由被命中时将服务器列表传递给ServerController,如果在配置文件中读取没有问题。 If there are problems, I want an exception to be thrown immediately. 如果有问题,我希望立即抛出异常。

I can't seem to find an entry point for my application, though, so I don't know how to perform actions on startup. 我似乎无法找到我的应用程序的入口点,所以我不知道如何在启动时执行操作。

Does anyone know how to do this? 有谁知道如何做到这一点? I'm using Play 2.5.x. 我正在使用Play 2.5.x.

If you're using the latest version of Play, it looks on startup for any class called Module that is in the root package (that is, there is no package definition at the top of the file). 如果您使用的是最新版本的Play,它会在启动时查找根软件包中名为Module任何类(即文件顶部没有package定义)。 Here is an example taken from the latest Activator template for Play 2.5.x, which I have modified for demonstration of running code on application startup and shutdown: 以下是Play 2.5.x的最新Activator模板的示例,我已经修改了该模板,用于演示在应用程序启动和关闭时运行的代码:

In services/Say.scala , this would be a simple service to say "Hello!" services/Say.scala ,这将是一个简单的服务,说“你好!” on startup and "Goodbye!" 在启动和“再见!” when the application shuts down: 当应用程序关闭时:

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

Some further resources you may find useful are the Scala dependency injection (DI) documentation and the Guice documentation . 您可能会发现一些有用的资源是Scala依赖注入(DI)文档Guice文档 Guice is the default DI framework used by Play. Guice是Play使用的默认DI框架。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM