让我说我有一些其他演员服务层演员常用的。例如,存储和检索域对象的注册表服务:
case class DomainObject(id: UUID)
class Registry extends akka.actor.Actor {
def receive: Receive = {
case o: DomainObject => store(o) // save or update object
case id: UUID => sender ! retrieve(id) // retrieve object and send it back
}
}
我不想将此类注册表的实例明确传递给可能使用它的所有actor。而不是它,我希望他们能够以某种方式“找到”它。
为此我可以想到两个解决方案:
Identify
消息:每个注册管理机构用户actor都知道某些配置中的注册管理机构名称,并且能够向其发送标识消息。收到AgentIdentity
消息后,我们很高兴:
val registryName = ... // some name
val registryId = ... // some id
var registry = _
def preStart() {
context.actorSelection(registryName) ! Identify(registryId)
}
def receive: Receive = {
case ActorIdentity(`registryId`, ref) => registry = ref
}
我不喜欢这种方式,因为在用户演员初始化之后有一个阶段,当我们不知道系统中是否有注册表,因此我们不知道我们是否能够操作。
Akka Extensions:我可以创建一个扩展名:
一个。在初始化时在给定的Actor System中创建Registry actor的实例;
湾通过Extension中的某些方法将此actor返回给需要它的用户。
object RegistryKey extends ExtensionKey[RegistryExtension]
class RegistryExtesion(system: ExtendedActorSystem) extends RegistryKey {
val registry = system.actorOf(Props[Registry], "registry")
}
问题是:哪种方法更好,Akka Extesions可以用于此吗?
答案 0 :(得分:3)
我认为扩展的想法是好的,只要你的注册表演员总是在同一个ActorSystem
。
或者,使用actorSelection
(改编自Remote Lookup):
class RegistryClient extends Actor {
val path = "/path/to/registry/actor"
context.setReceiveTimeout(3.seconds)
def sendIdentifyRequest(): Unit =
context.actorSelection(path) ! Identify(path)
def receive = {
case ActorIdentity(`path`, Some(ref)) ⇒
context.setReceiveTimeout(Duration.Undefined)
context.become(active(ref))
case ActorIdentity(`path`, None) ⇒
throw new RuntimeException("Registry not found")
case ReceiveTimeout ⇒ sendIdentifyRequest()
}
def active(registry: ActorRef): Actor.Receive = {
// use the registry
}
}
这适用于远程或本地演员。
让我们来看看扩展解决方案。 Actors are created asynchronously。因此,如果actor无法初始化,则在调用actorOf
时,扩展构造函数不会失败。
如果你想确定演员未能初始化,那么一种了解方法就是ask
演员将会回复并Await
作出回应。如果演员没有回复,Await
将抛出TimeoutException
。
class RegistryExtension(system: ExtendedActorSystem) extends Extension {
val registry = system.actorOf(Props[Registry], "registry")
implicit val timeout: Timeout = Timeout(500.millis)
val f = registry ? "ping" // Registry should case "ping" => "pong"
Await.result(f, 500.millis) // Will throw a TimeoutException if registry fails
// to respond
}
第一次拨打TimeoutException
时,RegistryExtension(system).registry
会被抛出。
答案 1 :(得分:3)
Cake Pattern或依赖注入库如subcut如何。
Derek Wyatt在他的书“Akka Concurrency”中提到DI,而不是使用太多的演员来查找演员: http://www.artima.com/forums/flat.jsp?forum=289&thread=347118