Я створив ін'єкцію залежностей за допомогою проекту Guice in Spray, як описано в це підручник.
Мой модуль Guice:
class ActorsModule extends AbstractModule with ScalaModule with GuiceAkkaActorRefProvider {
override def configure() {
bind[Actor].annotatedWith(Names.named(GenesActor.name)).to[GenesActor]
bind[Actor].annotatedWith(Names.named(SearchSegmentsActor.name)).to[SearchSegmentsActor]
bind[Actor].annotatedWith(Names.named(CollectionsFinderActor.name)).to[CollectionsFinderActor]
bind[Actor].annotatedWith(Names.named(HttpServiceActor.name)).to[HttpServiceActor]
}
@Provides
@Named(GenesActor.name)
def provideGenesActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, GenesActor.name)
@Provides
@Named(SearchSegmentsActor.name)
def provideSearchSegmentsActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, SearchSegmentsActor.name)
@Provides
@Named(CollectionsFinderActor.name)
def provideCollectionsFinderActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, CollectionsFinderActor.name)
}
У мене є сервер http актор, який отримує ін'єкціями інших акторів і пересилає повідомлення цим акторам:
object HttpServiceActor extends NamedActor {
override final val name: String = "HttpServiceActor"
}
class HttpServiceActor @Inject()(@Named(SearchSegmentsActor.name) searchSegmentsActor: ActorRef,
@Named(CollectionsFinderActor.name) collectionsFinderActor: ActorRef,
@Named(GenesActor.name) genesActor: ActorRef)
extends Actor with SearchHttpService with ActorLogging {
def actorRefFactory = context
def receive = runRoute(
sprayRoute(searchSegmentsActor, collectionsFinderActor, genesActor) ~
staticRoute)
}
і мені потрібно періодично надсилати повідомлення одному із введених акторів, тому мій головний метод виглядає так:
val injector = Guice.createInjector(
new ConfigModule(),
new AkkaModule(),
new DaoModule(),
new ActorsModule()
)
implicit val system = injector.getInstance(classOf[ActorSystem])
val service = system.actorOf(GuiceAkkaExtension(system).props(HttpServiceActor.name))
val collectionsActor = system.actorOf(GuiceAkkaExtension(system).props(CollectionsFinderActor.name))
system.scheduler.schedule(0 seconds, 1 minutes, collectionsActor, new RefreshCollections())
IO(Http) ! Http.Bind(service, system.settings.config.getString("app.interface"), system.settings.config.getInt("app.port"))
Насправді я бачу, що у мене є 2 екземпляри CollectionsFinderActor - один отримує заплановані повідомлення кожні 1 хвилину, а другий отримує повідомлення, переслані HttpServiceActor
Звичайно, це не те, що я очікую - я хочу, щоб той самий екземпляр CollectionsFinderActor отримав обидва повідомлення.
Що я роблю неправильно?
Відповіді:
2 для відповіді № 1Швидке відгадування. Якщо я пам’ятаю, за замовчуванням guice створює новий екземпляр служби кожного разу, коли ви про це просите. Принаймні, це не обіцяє використовувати їх повторно.
Вам доведеться вводити акторну систему та шукатиактор ref кожен раз, коли вам це потрібно. Незначним вдосконаленням може бути додавання послуги, яка охопить систему акторів та спілкування з акторами. Тоді вводьте цю нову послугу замість акторів тощо.
Це спосіб, описаний авторами рамки:
0 для відповіді № 2
Я вирішив проблему, додавши анотацію @Singleton для надання методуGenesActorRef
@Provides
@Named(GenesActor.name)
def provideGenesActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, GenesActor.name)