该实例的Akka Actor Path

时间:2016-03-30 15:14:30

标签: java playframework playframework-2.0 akka

我正在使用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。 请纠正我出错的地方。 我无法看到演员使用此路径。 我觉得,我跟踪路径的方式是错误的。 请指正。 比

1 个答案:

答案 0 :(得分:3)

请耐心等待,这需要一些时间才能完成,但它应该让你知道该怎么做。注意:我假设您仍然使用Play 2.4.x并且还没有更新到Play 2.5.x.而且你使用Java(虽然如果你能够切换,我会推荐Akka Scala API)。

第1步:定义处理WebSocket连接的actor

在您的控制器中,您可以写下:

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()

第2步:定义如何管理所有WebSocket参与者

一般情况下,您有两种选择 - 要么是&#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
            ...
        }
    }
 }

第3步:将所有内容放在一起

现在,请记住上面的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是键,值是某些特定于用户的属性或任何您想要的内容。