不同的 Akka Actor 实例接收消息
Different Akka Actor instances receive messages
我按照 this 教程中所述在 Spray 项目中使用 Guice 创建了依赖注入。
我的 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 的同一个实例将接收这两条消息。
我做错了什么?
快猜。如果我记得的话,默认情况下,每次您请求时,guice 都会创建一个新的服务实例。至少,它不承诺重用它们。
您将不得不注入 actor 系统,并在每次需要时查找 actor 引用。轻微的改进可能是添加一项服务,该服务将包装演员系统和与演员的沟通。然后注入这个新服务而不是演员等
这就是 framework 作者描述的方式:
我通过向 provideGenesActorRef 方法添加 @Singleton 注释解决了这个问题
@Provides
@Named(GenesActor.name)
def provideGenesActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, GenesActor.name)
我按照 this 教程中所述在 Spray 项目中使用 Guice 创建了依赖注入。
我的 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 的同一个实例将接收这两条消息。
我做错了什么?
快猜。如果我记得的话,默认情况下,每次您请求时,guice 都会创建一个新的服务实例。至少,它不承诺重用它们。
您将不得不注入 actor 系统,并在每次需要时查找 actor 引用。轻微的改进可能是添加一项服务,该服务将包装演员系统和与演员的沟通。然后注入这个新服务而不是演员等
这就是 framework 作者描述的方式:
我通过向 provideGenesActorRef 方法添加 @Singleton 注释解决了这个问题
@Provides
@Named(GenesActor.name)
def provideGenesActorRef(@Inject() system: ActorSystem): ActorRef = provideActorRef(system, GenesActor.name)