1

我正在將Play 2.3.x應用程序遷移到Play 2.5.x,並且在使用依賴注入時遇到了一些問題。如何正確使用DI來注入Play控制器的構造函數?

在2.3中,我有一個特性HasRemoteActor,控制器會根據配置混合引用一些遠程參與者。由於這需要應用程序的配置對象,現在要求它變成一個類,因此可以注入配置。這裏是我的嘗試:

/* 
    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://[email protected]$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) { 

    // ... 

} 

然而,當我開始我的申請,我覺得演員系統始終未能找到它的端口(即使沒有什麼是偵聽該端口),不考慮的端口號。

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。

我試着在我的build.sbt中加入routesGenerator := InjectedRoutesGenerator,並在@前加上了我的注入路由的相關控制器,但仍然發現相同的運行時異常。

有沒有人有建議?

+0

「無法綁定」通常意味着您已經擁有使用此端口的應用程序,請嘗試將您的配置更改爲使用其他端口。 – vdebergue

+0

@vdebergue這些端口沒有被TCP或UDP使用。 – erip

回答

1

我不會爲此使用繼承。相反,我會去這樣的事情(我要你用Guice的假設):

@Singleton 
class RemoteActorAdapter @Inject() (env: Environment, conf: Configuration) { 

    // all other initialization code 
    val client: ActorRef = ??? 

} 

在想要使用這些東西的控制:

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

這樣的伎倆是通過使用提供者,您將綁定的初始化等推遲到需要的時候。

+0

儘管我比我嘗試的更喜歡這種方法,但我仍然發現我遇到綁定錯誤。 – erip

+0

我認爲它沒有將'RemoteActorAdapter'綁定爲一個singleton ...你知道如何在'Module.scala'中正確地綁定這個嗎? – erip

+0

所以使用'Provider'的目的是推遲初始化。初始化是否是第一次工作,但後來失敗了,因爲它沒有重新使用實例?還是在第一次嘗試時也失敗?在前一種情況下,您可以嘗試如下操作:在(新的SingletonScope())'中綁定(classOf [RemoteActorAdapter])。到(classOf [RemoteActorAdapter])。在後一種情況下,我懷疑這與依賴注入有什麼關係。 – rethab

相關問題