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以適應您檢查配置的需要。