我想通过使用类名创建一个Akka actor,如图所示。 我尝试了很多变体的system.actorOf(new Props(theProcessor.getClass),name =“Test”), 但我无法让这个工作。从类加载器创建Actor的任何想法
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 :(得分:7)
您可以使用Java API(仅用于Props实例化):
val myActor = system.actorOf(
new Props( Class.forName( "myActorClassName" ).asInstanceOf[Class[Actor]] )
)
重要的部分是new
关键字。如果省略它,则将使用Scala API,而不允许按类实例化。
答案 1 :(得分:7)
听起来你想要使用与ActorSystem使用的ClassLoader相同的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"))
答案 2 :(得分:4)
(如堆栈跟踪中所示)您必须使用
system.actorOf(Props[TestProcessor])
(没有new
关键字,您传递了一种类型)system.actorOf(Props(new TestProcessor()))
(new
关键字,您传递实例)答案 3 :(得分:1)
如果你可以从String中获取Props,那么你可以从String中获取一个actor。以下是如何从字符串中获取道具:
(defn split-last [re s]
(let [pattern (re-pattern (str re "(?!.*" re ")"))]
(split-first pattern s)))
(split-last #"\." "abc.def.ghi")
=> ["abc.def" "ghi"]
(split-last #"<>" "abc<>def<>ghi")
=> ["abc<>def" "ghi"]
我把它放了,因为没有其他答案使用Props.apply(Class.forName( "myActorClassName" ).asInstanceOf[Class[Actor]])
- 对Akka来说是一个相对较新的增强。传递构造函数参数很容易,例如当前的actorRef,例如:
Props.apply