Scala 如何正确使用DI注入播放控制器';谁的构造函数?

Scala 如何正确使用DI注入播放控制器';谁的构造函数?,scala,dependency-injection,playframework,guice,akka-remoting,Scala,Dependency Injection,Playframework,Guice,Akka Remoting,我正在将Play 2.3.x应用程序迁移到Play 2.5.x,在使用依赖项注入时遇到了一些问题 在2.3中,我有一个traithasmoteactor,控制器会根据配置混入该trait,以引用某个远程参与者。因为这需要应用程序的config对象,所以现在需要它成为一个类,以便可以注入配置。以下是我的尝试: /* Dummy controller that has environment and configuration manually injected. */ class Confi

我正在将Play 2.3.x应用程序迁移到Play 2.5.x,在使用依赖项注入时遇到了一些问题

在2.3中,我有一个trait
hasmoteactor
,控制器会根据配置混入该trait,以引用某个远程参与者。因为这需要应用程序的config对象,所以现在需要它成为一个类,以便可以注入配置。以下是我的尝试:

/*
   Dummy controller that has environment and configuration manually injected.
*/
class ConfigurationController(env: play.api.Environment,
                              conf: play.api.Configuration) extends Controller {

}

/*
  Dummy controller that has environment and configuration manually injected, but 
  sets up a remote client.
*/ 
class RemoteActorController(env: play.api.Environment, conf: play.api.Configuration)
  extends ConfigurationController(env, conf) {

  protected val remoteActorName = "foo"
  private val remoteActorConf = conf.underlying.getConfig(remoteActorName)
  private val system = ActorSystem("HttpServerSystem", ConfigFactory.load())

  private val tcpInfo = remoteActorConf.getConfig("akka.remote.netty.tcp")
  private val hostname = tcpInfo.getString("hostname")
  private val port = tcpInfo.getString("port")

  val path = s"akka.tcp://PubSubMember@$hostname:$port/system/receptionist"

  private val initialContacts = Set(ActorPath.fromString(path))


  protected val client = system.actorOf(
    ClusterClient.props(ClusterClientSettings(system).withInitialContacts(
        initialContacts)),
    "ClusterClient"
  )
}

/*
   Actual controller whose actions correspond to endpoints in `conf/routes`.
*/
@Singleton
class BarController @Inject()(env: play.api.Environment,
                              conf: play.api.Configuration) extends
    RemoteActorController(env, conf) {

    // ...

}
然而,当我启动我的应用程序时,我发现actor系统总是无法找到它的端口(即使没有任何东西在该端口上侦听),而不管端口号如何

play.api.UnexpectedException: Unexpected exception[ProvisionException: Unable to provision, see the following errors:

1) Error injecting constructor, org.jboss.netty.channel.ChannelException: Failed to bind to: /127.0.0.1:8888
注入的时间似乎有问题,但我对DI太陌生了,所以调试它有困难

我尝试将
routesGenerator:=InjectedRoutesGenerator
添加到我的
build.sbt
中,并在我的注入路由的关联控制器前面加上
@
,但仍然发现相同的运行时异常


有人有什么建议吗?

我不会为此使用继承。相反,我会选择这样的方式(我假设您使用的是guice):

在要使用这些东西的控制器中:

class MyController @Inject() (remoteAdapterProvider: Provider[RemoteActorAdapter]) extends Controller {
  def index = Action {
    remoteAdapterProvider.get.client ! Hello
  }
}

因此,诀窍在于,通过使用提供程序,您可以将绑定等的初始化推迟到需要时。

“绑定失败”通常意味着您已经有了使用此端口的应用程序,尝试更改您的配置以使用其他端口。@vdebergue这些端口既不被TCP也不被UDP使用。虽然我比我尝试的方法更喜欢这种方法,但我仍然发现我遇到了绑定错误。我认为它没有将
RemoteActRadapter
作为一个单例绑定。。。您知道如何在
Module.scala
中正确绑定它吗?因此使用
提供程序的目的是推迟初始化。初始化是否第一次工作,但随后失败,因为它没有重新使用实例?还是第一次尝试也失败了?在前一种情况下,您可以尝试以下操作:
bind(classOf[remoteActorapter])。to(classOf[remoteActorapter])。In(new SingletonScope())
。在后一种情况下,我怀疑这与依赖注入有关。我想我发现了问题。。。它与DI完全分离。相反,这是
ConfigFactory.load()
调用——这导致了一个问题,并显示为绑定错误!
class MyController @Inject() (remoteAdapterProvider: Provider[RemoteActorAdapter]) extends Controller {
  def index = Action {
    remoteAdapterProvider.get.client ! Hello
  }
}