繁体   English   中英

Play框架中的Scala依赖注入

[英]Scala Dependency Injection in Play Framework

我是Scala,PlayFramework和依赖注入的新手。 我下载了示例scala play框架代码。 有人可以向我解释为什么我们需要注入Clock和appLifeCycle吗? 上面已经提到了它,因此不需要注入它吗? 这里发生了什么? 为什么我们通常需要对Web框架执行此操作?

package services

import java.time.{Clock, Instant}
import javax.inject._
import play.api.Logger
import play.api.inject.ApplicationLifecycle
import scala.concurrent.Future

/**
 * This class demonstrates how to run code when the
 * application starts and stops. It starts a timer when the
 * application starts. When the application stops it prints out how
 * long the application was running for.
 *
 * This class is registered for Guice dependency injection in the
 * [[Module]] class. We want the class to start when the application
 * starts, so it is registered as an "eager singleton". See the code
 * in the [[Module]] class to see how this happens.
 *
 * This class needs to run code when the server stops. It uses the
 * application's [[ApplicationLifecycle]] to register a stop hook.
 */
@Singleton
class ApplicationTimer @Inject() (clock: Clock, appLifecycle: ApplicationLifecycle) {

  // This code is called when the application starts.
  private val start: Instant = clock.instant
  Logger.info(s"ApplicationTimer demo: Starting application at $start.")

  // 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 { () =>
    val stop: Instant = clock.instant
    val runningTime: Long = stop.getEpochSecond - start.getEpochSecond
    Logger.info(s"ApplicationTimer demo: Stopping application at ${clock.instant} after ${runningTime}s.")
    Future.successful(())
  }
}

我假设您正在使用Lightbend的Play Scala Seed ,其中包含您发布的代码示例。

如果查看java.time.Clock的文档,您会注意到它说(强调我):

应用程序的最佳实践是将Clock传递到需要当前时刻的任何方法中。 依赖项注入框架是实现此目标的一种方法。 {..省略代码示例..}这种方法允许在测试过程中使用备用时钟 ,例如固定时钟或偏移时钟

最终依赖注入的目的是允许您定义要注入类或对象的接口 ,并配置在短短的一个地方是接口的实现。 另一种选择是必须更新多个文件中的硬编码依赖关系,这可能是混乱且容易出错的。 在Play Scala Seed项目中,您会注意到一个名为app/Module.scala的文件。 该文件是您可以配置绑定的地方,它们将在应用程序启动时自动绑定。 注意我们绑定Clock实现的行:

class Module extends AbstractModule {

  override def configure() = {
    // Use the system clock as the default implementation of Clock
    bind(classOf[Clock]).toInstance(Clock.systemDefaultZone)
    // Ask Guice to create an instance of ApplicationTimer when the
    // application starts.
    bind(classOf[ApplicationTimer]).asEagerSingleton()
    // Set AtomicCounter as the implementation for Counter.
    bind(classOf[Counter]).to(classOf[AtomicCounter])
  }

}

此配置表示“当我的应用程序启动时,无论我在哪里注入Clock都应使用Clock.systemDefaultZone 。” 如果希望ApplicationTimer在测试期间使用其他时钟,则可以执行以下操作:

import play.api.{Environment, Mode}

// Notice that we include the environment
class Module(environment: Environment) extends AbstractModule {
  override def configure() = {
    // Use the system clock as the default implementation of Clock
    environment.mode match {
      case Mode.Prod | Mode.Dev => {
        bind(classOf[Clock]).toInstance(Clock.systemDefaultZone)
      }
      case Mode.Test => {
        // Specifically use UTC clock in tests, because maybe it's easier to write assertions that way
        // You could inject anything here and the ApplicationTimer would use it during tests
        bind(classOf[Clock]).toInstance(Clock.systemUTC())
      }
    }
    bind(classOf[ApplicationTimer]).asEagerSingleton()
    bind(classOf[Counter]).to(classOf[AtomicCounter])
  }
}

您可以在根包的其他位置定义模块(即,文件package com.example.whatever不在文件顶部的任何声明),它们也将自动加载。 否则,您需要在conf/application.conf中添加一个绑定,以将模块的名称添加到play.modules.enabled键中。 您可以在Play Scala种子中看到已注释掉的示例。 我还在这里写的另一个答案中做得更深入。

至于ApplicationLifecycle ,这是Play提供的特殊模块,您可以使用自己的绑定重写它,但是我不确定为什么要这么做。 它可以让您访问在应用程序关闭之前执行的挂钩。 再次,注入该组件是因为将其交换出来很简单。 想象有100个模块,它们全部取决于应用程序生命周期。 默认情况下,它绑定到DefaultApplicationLifecycle (您可以在此处看到它的绑定)。 如果您已在所有100个模块中对DefaultApplicationLifecycle进行了硬编码, DefaultApplicationLifecycle切换到其他生命周期,则必须更新每个模块。 使用依赖注入,您只需要配置绑定以使用不同的生命周期,并且100个模块将自动使用它。

暂无
暂无

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

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