Как правильно использовать DI для внедрения конструктора контроллера Play?
Я перевожу приложение Play 2.3.x в Play 2.5.x и у меня возникают некоторые проблемы с использованием внедрения зависимостей.
В 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://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) {
// ...
}
Однако, когда я запускаю свое приложение, я обнаруживаю, что система субъекта всегда не может найти свой порт (даже если на этом порте ничего не прослушивается) независимо от номера порта.
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
и префикс связанных контроллеров моих введенных маршрутов с @
, но все же найти те же исключения во время выполнения.
У кого-нибудь есть предложения?
1 ответ
Я бы не использовал наследство для этого. Вместо этого я бы пошел на что-то вроде этого (я предполагаю, что вы используете хитрость):
@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
}
}
Таким образом, хитрость заключается в том, что с помощью провайдера вы откладываете инициализацию привязки и т. Д. До времени, когда это необходимо.