我想要设置Akka演员来处理正在播放的网络插座。
我已经定义了一个简单的actor来通过web socket发送消息:
package actors;
import akka.actor.*;
public class MyWebSocketActor extends UntypedActor {
public static Props props(ActorRef out) {
return Props.create(MyWebSocketActor.class, out);
}
private final ActorRef out;
public MyWebSocketActor(ActorRef out ) {
this.out = out;
}
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
out.tell(message, self());
}
}
}
在Application控制器中,我有了web-socket:
package controllers;
import play.*;
import play.mvc.*;
import akka.util.*;
import views.html.*;
import actors.MyWebSocketActor;
import play.libs.F.*;
public class Application extends Controller {
public static Result index() {
return ok(index.render("Your new application is ready."));
}
public static WebSocket<String> socket() {
return WebSocket.withActor(MyWebSocketActor::props);
}
}
直到现在,一切都按照我的预期运作。现在,在控制器中我试图将消息传递给该actor。我试过了:
public class Messages extends Controller {
private static final Form<Message> messageForm = Form.form(Message.class);
@BodyParser.Of(BodyParser.Json.class)
public static Result list(Integer page) {
// --- Render
ActorRef myActor = Akka.system().actorOf(Props.create(MyWebSocketActor.class));
String message = "test";
myActor.tell(message, ActorRef.noSender());
//
}
但是出现错误:“无法调用该操作,最终出现错误:java.lang.IllegalArgumentException:在类actors.MyWebSocketActor上找不到匹配的构造函数,用于参数[]。
2014-08-05 05:50:23,503 - [INFO] - from play in pool-4-thread-4
Listening for HTTP on /0:0:0:0:0:0:0:0:9000
2014-08-05 05:51:02,887 - [ERROR] - from application in New I/O worker #1
! @6j5b25956 - Internal server error, for (GET) [/] ->
play.PlayExceptions$CompilationException: Compilation error[error: method tell in class ActorRef cannot be applied to given types;]
at play.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na]
at play.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na]
at scala.Option.map(Option.scala:145) ~[scala-library-2.11.1.jar:na]
at play.PlayReloader$$anon$1$$anonfun$play$PlayReloader$$anon$$taskFailureHandler$1.apply(PlayReloader.scala:297) ~[na:na]
at play.PlayReloader$$anon$1$$anonfun$play$PlayReloader$$anon$$taskFailureHandler$1.apply(PlayReloader.scala:292) ~[na:na]
at scala.Option.map(Option.scala:145) ~[scala-library-2.11.1.jar:na]
at play.PlayReloader$$anon$1.play$PlayReloader$$anon$$taskFailureHandler(PlayReloader.scala:292) ~[na:na]
at play.PlayReloader$$anon$1$$anonfun$reload$2.apply(PlayReloader.scala:325) ~[na:na]
at play.PlayReloader$$anon$1$$anonfun$reload$2.apply(PlayReloader.scala:325) ~[na:na]
at scala.util.Either$LeftProjection.map(Either.scala:377) ~[scala-library-2.11.1.jar:na]
at play.PlayReloader$$anon$1.reload(PlayReloader.scala:325) ~[na:na]
at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:107) ~[play_2.11-2.3.1.jar:2.3.1]
at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:105) ~[play_2.11-2.3.1.jar:2.3.1]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.1.jar:na]
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.1.jar:na]
at scala.concurrent.forkjoin.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1361) ~[scala-library-2.11.1.jar:na]
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) ~[scala-library-2.11.1.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) ~[scala-library-2.11.1.jar:na]
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) ~[scala-library-2.11.1.jar:na]
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) ~[scala-library-2.11.1.jar:na]
2014-08-05 05:51:03,084 - [WARN] - from play in New I/O worker #1
No application found at invoker init
2014-08-05 06:08:03,586 - [ERROR] - from application in New I/O worker #2
答案 0 :(得分:7)
我可以看到的一个问题是,在您的控制器中,您正在尝试实例化MyWebSocketActor
的新实例,但您没有给它正确的构造函数信息以允许创建新实例。问题是这一行:
ActorRef myActor = Akka.system().actorOf(Props.create(MyWebSocketActor.class));
在MyWebSocketActor中,您没有no-args构造函数。您有一个构造函数定义为:
public MyWebSocketActor(ActorRef out ) {
this.out = out;
}
现在,您正在MyWebSocketActor上的静态props
方法中正确执行此操作。如果您真的希望能够在控制器中实例化此actor的新实例(而不是查找现有实例),则需要在构造函数中使用ActorRef
(称为out
传入。如果你有,那么你可以修改你的代码如下:
ActorRef myActor = Akka.system().actorOf(MyWebSocketActor.props(outRef));
修改强>
现在,如果您想查找现有的actor而不是创建每个请求的actor,您首先需要确保已经创建并命名了要查找的actor实例,以便您可以查看它了。所以像这样:
Akka.system().actorOf(MyWebSocketActor.props(outRef), "myactor");
然后,在您的控制器中,您可以使用ActorSelection
找到预先存在的演员,如下所示:
ActorSelection myActorSel = Akka.system().actorSelection("/user/myactor");
ActorSelection
不是ActorRef
,也不共享某个基接口/抽象类。但它支持tell
操作的方式与ActorRef
相同,因此您可以在查找后调用tell
。如果你的演员存在这个名字,那么事情应该很好。
您可以在“通过ActorSelection识别参与者”一节中阅读有关ActorSelection
s here的更多信息。
答案 1 :(得分:3)
你的演员只有一个带参数的构造函数。使用actorOf创建actor时,不会传递该参数。这也是错误消息所说的,你的actor没有不带参数的构造函数。
有趣的是,您在actor中定义了一条静态props
消息。如果您使用它而不是在actorOf中创建Props,那么您将获得编译器警告; - )