2015-02-23 27 views
1

我有以下代码动态加载的演员,如果它的存在

lazy val restEndpoint = context.actorOf(Props[RestEndpoint], "RestEndpoint") 

不过,我想动态加载的演员,如果它的存在是有几个原因:

  1. 它可能不是在类路径,所以我不得不问问类加载器是否存在。
  2. 即使它在类路径上,我可能不想因为配置原因而加载它。
  3. RestEndpoint位于与此JAR文件相关的JAR文件中,因此我无法获得循环依赖关系。

是否有一些“简单”的方法来反射?请不要指向我关于Scala反射的文档,因为在那里并不容易。如果有一个Scala Reflection for Dummies讨论,我会很高兴看到这个。

一个工作示例将不胜感激。

回答

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) 
     } 
} 

虽然这增加了一些额外的样板,但我不认为这太糟糕。我可能会更多地减少样板。

类型安全还建议我看Akka ExtensionsExtendedActorSystem

5

反射对于不在classpath中的东西没有帮助。任何不在课程路径中的意思是"Java does not know about the existence of this entity."

现在,当涉及到任何实例化的actor(它并不重要,它甚至可以在所有Akka关心的替代宇宙中......),你可以通过ActorRef来引用它们:使用他们fully qualified地址(路径,嗯....替代的宇宙......好简单的,问你的备用自:p)的例子 -

val as = ActorSystem("myActorSystem") 

val refToRemoteActor: ActorSelection = as.actorSelection("akka.tcp://[email protected]: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消息),并使用remote Actor的答复的参考sender()

注意:如果有人在获取替代宇宙的演员时遇到问题,Akka尚未提供替代宇宙功能。但是,只要你能通过这个“量子隧道......或任何它的地狱”获得一条局域网电缆,你就可以实现它。

+1

其实你也可以只使用在'ActorSelection'的'resolveOne'方法检索'未来[ActorRef]'现在直接。 – LMeyer 2015-02-23 15:15:38

+0

@LMeyer Yup ...但我认为它与发送Identify消息和解析Actor发件人中的ActorRef是一样的。 – 2015-02-23 16:05:33

+0

所以我现在并没有真正对远程演员感兴趣,我真的只关心我如何动态加载演员,就像其他任何类一样,因为它的名字是“RestEnpoint” – 2015-02-23 20:55:34

0

我会试着找到另一种方式来处理你的循环依赖问题,如通过反射实例演员可以让你陷入困境,但它是可能的,下面的代码所示:

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 _ => 
    } 
} 

如果该类不不存在于类路径中,您将得到一个失败。您还可以将其他逻辑添加到tryAndInstantiate以适应您检查配置的需要。

相关问题