1

Я переношу приложение 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, что у меня возникают проблемы отладки его.

Я попытался добавить routesGenerator := InjectedRoutesGenerator в мой build.sbt и префиксами связанных контроллеров связанных с ними контроллеров с помощью @, но все равно найду те же исключения во время выполнения.

У кого-нибудь есть предложения?

+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» как одноэлементный ... знаете ли вы, как правильно это связывать в 'Module.scala'? – erip

+0

Таким образом, целью использования «Поставщика» было отложить инициализацию. Выполняется ли инициализация в первый раз, но потом сбой, поскольку он не повторяет использование экземпляра? Или это также терпит неудачу с первой попытки? В первом случае вы можете попробовать что-то вроде этого: 'bind (classOf [RemoteActorAdapter]). To (classOf [RemoteActorAdapter]). In (new SingletonScope())'. В последнем случае я сомневаюсь, что это имеет какое-либо отношение к инъекции зависимостей. – rethab

Смежные вопросы