我正在使用Java Play Framework。 我正在使用Web套接字进行客户端服务器交互。 在服务器端,我们还有响应客户端请求的actor。 我面临的问题: 我想,当客户端打开与服务器上的Hakka actor的Web套接字连接时,它实际上为该actor打开了一个池,然后我需要跟踪该实例的actor客户端路径,以便每当其他一些操作需要时放置在某个其他类中,该类通知此actor(使用已跟踪的实例路径)该操作已发生,然后此actor通知用户(客户端)已发生此操作。 我实际上正在使用
String ClientPushActorPath = akka.serialization.Serialization.serializedActorPath(self());
以上内容为了获取客户端用户实例的路径。 但是下次当我尝试用这条路径击中这个演员时,我无法找到这个演员。 我试图从另一个演员那里击中演员的方式是:
PushCacheManager cache = PushCacheManager.getInstance();
cache.load(qiid);
String ActorPath = cache.get("ClientPushActorPath");
ActorSelection ClientPushActor = system.actorSelection(ActorPath);
ClientPushActor.tell(m4, getSelf());
所以上面的代码简单地说,首先我去从缓存中获取苏格兰路径(它被缓存在内存中供将来使用)然后我尝试将该路径传递给actor选择。一旦我得到了actor的对象选择我用它告诉另一个演员我需要传递的消息是m4。 请纠正我出错的地方。 我无法看到演员使用此路径。 我觉得,我跟踪路径的方式是错误的。 请指正。 比
答案 0 :(得分:3)
请耐心等待,这需要一些时间才能完成,但它应该让你知道该怎么做。注意:我假设您仍然使用Play 2.4.x并且还没有更新到Play 2.5.x.而且你使用Java(虽然如果你能够切换,我会推荐Akka Scala API)。
在您的控制器中,您可以写下:
public static WebSocket<String> socket() {
return WebSocket.withActor(MyWebSocketActor::props);
}
这意味着每个WebSocket连接都将由类型为MyWebSocketActor
的actor实例处理。然后你必须像这样实现演员:
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("I received your message: " + message, self());
}
}
}
您看到的ActorRef out
参数实际上是底层角色(从Play生成)。你不需要对它做任何事情,只要记住,一旦你向这个out
演员发送了一些东西,他就会把它交给客户。
您还必须在routes
文件中定义正确的路线:
GET /ws controllers.Application.socket()
一般情况下,您有两种选择 - 要么是&#34;请查看&#34;上面创建的actor或者你提供了某种管理它们的机制(注册表类型)
步骤2.1:查找WebSocket演员
这里的优点是您不需要额外的注册表/经理或类似的。缺点是很难知道哪个actor服务于哪个WebSocket连接。
您可以使用actorSelection
:
system.actorSelection("system/websockets/*/handler");
这是有效的,因为正如我之前提到的,Play有生成的连接处理程序actor - 所以它们的地址是这样的:akka://application/system/websockets/42/handler
。同样,通过这种方式,您可以获得所有演员而不是单人(因为您不知道他们的经纪人号码)。
步骤2b:管理WebSocket演员 这里的优点是您可以完全管理演员并为他们分配各种信息。缺点是你还有一个演员可以照顾(虽然不是真的有问题,Akka很擅长这个)
您可以创建一个新的演员:
public class ManagerActor extends UntypedActor {
List<ActorRef> slaves;
public MyWebSocketActor() {
this.slaves = new ArrayList<>();
}
public void onReceive(Object message) throws Exception {
if (message instanceof RegisterMe) {
// a new WebSocket was created so we can register him
slaves.add(sender());
// also register a DeathWatch so that we know when the WebSocket actor dies
context.watch(sender());
} else if (message instanceof Terminated) {
// remove from the list
...
}
}
}
现在,请记住上面的WebSocket演员?他应该以某种方式向经理注册。同样,你可以通过两种方式做到这一点:你可以&#34;查找&#34;具有context.system.actorSelection("user/manager")
的管理器或者如果您已经有一个对管理器的引用(ActorRef
),您可以在创建WebSocket actor时将其作为构造函数参数提供
您可以使用每个演员都可以使用的preStart
方法进行注册:
public class MyWebSocketActor extends UntypedActor {
....
@Override
public void preStart() throws Exception {
context().system().actorSelection("user/manager").tell(RegisterMe, self());
super.preStart();
}
}
现在您拥有了由...管理的所有WebSocket演员,您可以定义他可以处理的新消息,并告诉他必须将m4
转发给客户端。请注意,您可以在Manager中使用类似Map
的内容 - 其中ActorRef
是键,值是某些特定于用户的属性或任何您想要的内容。