我有以下代码
lazy val restEndpoint = context.actorOf(Props[RestEndpoint], "RestEndpoint")
但是,我想动态加载actor,如果它存在的原因有以下几点:
有一种'简单'的方法可以反思地做到这一点吗?请不要指出Scala中有关反射的文档,因为那里没有什么容易的。如果有一个Scala Reflection for Dummies讨论,我会很感激地看着它。
非常感谢一个工作范例。
答案 0 :(得分:5)
反映对classpath
以外的事物没有帮助。任何不在类路径中的东西都意味着"Java does not know about the existence of this entity."
。
现在,当涉及到任何实例化的actor时(无论在哪里......甚至可以在所有Akka关心的替代宇宙中......),你可以通过{{1来引用它们通过使用他们的ActorRef
地址(路径,嗯......替代宇宙......嗯......简单,问你的替代自我:p)示例 -
fully qualified
如果val as = ActorSystem( "myActorSystem" )
val refToRemoteActor: ActorSelection = as.actorSelection( "akka.tcp://my-sys@host.example.com:5678/user/service-b" )
// Now You can tell anything to your ActorSelction. But you can not ask them.
refToRemoteActor ! "my-message"
需要ActorRef
,则需要向演员发送消息,例如内置的remote Actor
消息,并使用Identify
参考sender()
的回复。
注意:如果有人在为alternate-universe获取Actors时遇到问题,remote Actor
还没有提供Alternate-universe功能。但是,你可以实现它,就好像你可以通过那个量子隧道获得LAN电缆......或者不管它到底是什么"。
答案 1 :(得分:0)
我会尝试找到另一种处理循环依赖问题的方法,因为通过反射实例化actor会让你遇到麻烦,但是有可能如下面的代码所示:
package code
import akka.actor._
import scala.util._
object Test extends App{
val system = ActorSystem("test")
val shouldSucceed = tryAndInstantiate("code.MyTestActor")
println(shouldSucceed)
val shouldFail = tryAndInstantiate("code.FooTestActor")
println(shouldFail )
def tryAndInstantiate(name:String):Try[ActorRef] = {
Try{
val clazz = Class.forName(name)
system.actorOf(Props(clazz))
}
}
}
class MyTestActor extends Actor{
def receive = {
case _ =>
}
}
如果类路径中不存在该类,则会出现Failure。您还可以向tryAndInstantiate
添加其他逻辑,以满足您检查配置的需要。
答案 2 :(得分:0)
非常高兴我们有Typesafe支持合同。这是我们提出的解决方案。我测试了代码,它的工作原理。注意:没有必要反思,这让我很开心。
def actorRefForName(className: String) = try {
val actorClass = Class.forName(className)
Some(context.actorOf(Props(actorClass), actorClass.getSimpleName))
} catch {
case classNotFoundException: ClassNotFoundException =>
log.info(s"class $className not found. This actor will not be used")
None
}
. . .
lazy val kinesisProducer =
actorRefForName("com._3tierlogic.KinesisManager.producer.KinesisProducer")
. . .
def receive = {
case Start =>
kinesisProducer match {
case Some(kinesisProducerRef) =>
log.info("Starting " + kinesisProducerRef.path.name)
kinesisProducerRef ! Start
case None =>
log.info("There is no Kinesis Producer actor to start.")
}
case Started =>
// foreach is a little confusing when there is only Some or None, but
// basically we can only use our actorRef if there is one. EK
kinesisProducer.foreach { kinesisProducerRef =>
if (sender.equals(kinesisProducerRef)) {
log.info(kinesisProducerRef.path.name + " Started")
log.info("Starting " + restEndpointRef.path.name)
IO(Http)(context.system) ! Http.Bind(restEndpointRef, "0.0.0.0", port = 8061)
}
}
虽然这增加了一些额外的样板,但我认为这不太糟糕。我可能有办法更多地减少样板。
Typesafe还建议我查看Akka Extensions和ExtendedActorSystem