2013-03-28 58 views
3

我想通過使用類名創建一個Akka actor,如圖所示。 我已經嘗試了很多變種的system.actorOf(新道具(theProcessor.getClass),name =「Test」), ,但我無法讓這個工作。從類加載器創建一個演員的任何想法如何創建一個名爲Akka的演員

package com.test 

import akka.actor.{Props, Actor, ActorRef, ActorSystem} 

object Main { 
    def main(args: Array[String]) { 
    ActorFromString("Test") 
    } 
} 

object ActorFromString { 
    implicit val system = ActorSystem("Test") 
    def apply(name: String): ActorRef = { 
    val className = "com.test." + name + "Processor" 
    val theProcessor: Actor = Class.forName(className).newInstance().asInstanceOf[Actor] 
    system.actorOf(new Props(theProcessor.getClass), name = "Test") 
    } 
} 

class TestProcessor extends Actor { 
    def receive = { 
    case data => println("processing data") 
    } 
} 

Exception in thread "main" akka.actor.ActorInitializationException: 
You cannot create an instance of [com.test.TestProcessor] explicitly using the constructor (new). 
You have to use one of the factory methods to create a new actor. Either use: 
'val actor = context.actorOf(Props[MyActor])'  (to create a supervised child actor from within an actor), or 
'val actor = system.actorOf(Props(new MyActor(..)))' (to create a top level actor from the ActorSystem) 
at akka.actor.ActorInitializationException$.apply(Actor.scala:166) 
at akka.actor.Actor$class.$init$(Actor.scala:377) 
at com.test.TestProcessor.<init>(ActorFromString.scala:20) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) 
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
at java.lang.reflect.Constructor.newInstance(Constructor.java:525) 
at java.lang.Class.newInstance0(Class.java:374) 
at java.lang.Class.newInstance(Class.java:327) 
at com.test.ActorFromString$.apply(ActorFromString.scala:15) 
at com.test.Main$.main(ActorFromString.scala:7) 
at com.test.Main.main(ActorFromString.scala) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:601) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 

Process finished with exit code 143 
+0

我意識到我的問題可能不是很清楚。關鍵在於傳遞一個名字並從中構建一個演員。這個名字並不是事先知道的,而是來自一組可能的類名。這裏的測試例子只是一個類「TestProcessor」,可能有另一個叫做「Test2Processor」等等...... – user2036540 2013-03-28 06:24:11

+3

我想我已經解決了它。我需要在Props中創建一個thing.system.actorOf(Props(Class.forName(className).newInstance()。asInstanceOf [Actor]),name = device) – user2036540 2013-03-28 06:50:53

回答

3

(如堆棧跟蹤指示),你可以選擇使用

  • system.actorOf(Props[TestProcessor])(無new關鍵字,你傳遞一個類型)
  • system.actorOf(Props(new TestProcessor()))new關鍵字,您傳遞一個實例)
+2

要挑剔,你不會傳遞一個實例,您傳遞一個名稱參數,每次需要一個新的actor實例時都會執行該參數。 – 2013-03-28 08:58:42

+0

@EndreVarga true。申請方法簽名是'def apply(creator:⇒Actor):Props = default.withCreator(creator)'。這個論點是一個創造演員的實例。 – 2013-03-28 09:18:28

6

您可以使用Java API(僅用於Props insta ):

val myActor = system.actorOf( 
    new Props(Class.forName("myActorClassName").asInstanceOf[Class[Actor]]) 
) 

重要的部分是new關鍵字。如果您忽略它,您將使用Scala API,而不允許按類實例化。

6

聽起來像你想要使用相同的ClassLoader作爲你的ActorSystem, 使用相同的ClassLoader,所以這很容易通過定製的Akka擴展來解決(警告,沒有實際編譯,但你會得到它的要點)

import akka.actor.{ Extension, ExtensionId, ExtensionIdProvider, ExtendedActorSystem, DynamicAccess } 
// This will be instantiated once per ActorSystem instance 
class Reflection(access: DynamicAccess) extends Extension { 
    // Loads the Class with the provided Fully Qualified Class Name using the given DynamicAccess 
    // Throws exception if it fails to load 
    def actorClassFor(fqcn: String) = access.getClassFor[Actor](fqcn).get 
} 
// This is how we access the Reflection extension, you can view it as an ActorSystemLocal 
object Reflect extends ExtensionId[Reflection] with ExtensionIdProvider { 
    override def lookup = Reflect 
    override def createExtension(system: ExtendedActorSystem) = new Reflection(system.dynamicAccess) 
} 
// Load the extension if not already loaded, return the instance for this ActorSystem and call the actorClassFor 
system.actorOf(Props(Reflect(system).actorClassFor("com.test." + name + "Processor")) 
1

如果你可以從一個字符串得到一個道具,那麼你可以從一個字符串中獲得一個actor。以下是如何從一個字符串獲得道具:

Props.apply(Class.forName("myActorClassName").asInstanceOf[Class[Actor]]) 

我把這個,因爲沒有任何其他的答案使用Props.apply - 一個相對較新的增強阿卡。很容易傳入構造函數參數,例如當前actorRef,例如:

def selfActorRef = context.self 
val gateKeeperRef = context.actorOf(
    Props.apply(Class.forName(findGateKeeperName).asInstanceOf[Class[Actor]], 
    selfActorRef) 
)