2013-03-28 33 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) 
)