1

我有以下代码

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

但是,我想动态加载演员,如果它在那里有几个原因:

  1. 它可能不在类路径上,所以我必须询问类加载器是否存在。
  2. 即使它在类路径中,出于配置原因,我也可能不想加载它。
  3. RestEndpoint 在另一个 JAR 文件中,该文件已经依赖于这个 JAR 文件,所以我不能有循环依赖。

是否有一些“简单”的方法可以反思性地做到这一点?请不要指向我关于 Scala 反射的文档,因为那里没有什么容易的。如果有 Scala Reflection for Dummies 讨论,我将不胜感激。

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

4

3 回答 3

5

对于不在你的classpath. 任何不在类路径中的东西都意味着"Java does not know about the existence of this entity.".

现在,当涉及到任何实例化的演员(无论在哪里......它甚至可以在所有 Akka 关心的替代宇宙中......),您可以ActorRef通过使用他们的fully qualified地址(路径,嗯....替代宇宙...嗯...简单,问你的替代自我:p)示例 -

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()来自该 的回复的引用remote Actor

注意:如果有人在获取替代宇宙的 Actors 时遇到问题,Akka暂时不提供替代宇宙功能。但是,只要你能通过那个“量子隧道......或者不管它是什么鬼东西”,你就能得到它。

于 2015-02-23T05:36:35.890 回答
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满足您检查配置的需要。

于 2015-02-24T16:56:44.943 回答
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 ExtensionsExtendedActorSystem

于 2015-02-25T16:51:05.613 回答