Java 如何在Play framework 2应用程序中存储Akka参与者列表?

Java 如何在Play framework 2应用程序中存储Akka参与者列表?,java,playframework,akka,Java,Playframework,Akka,我有一个Play framework 2应用程序,它可以接收数据并通过WebSocket将数据发送给多个客户端。我使用Akka演员处理WebSocket,就像在中一样。我还有一个WebSocketRouter类,它扩展了UntypedActor,并包含路由逻辑(决定将系统接收到的数据传递给哪个客户端)。我知道我可以使用Akka的路由器功能,但这不是我目前的问题。问题是我必须存储所有活动客户端的列表。现在我将它存储在WebSocketRouter类的静态列表中。这是编写概念验证原型的最快方式,但它

我有一个Play framework 2应用程序,它可以接收数据并通过WebSocket将数据发送给多个客户端。我使用Akka演员处理WebSocket,就像在中一样。我还有一个
WebSocketRouter
类,它扩展了
UntypedActor
,并包含路由逻辑(决定将系统接收到的数据传递给哪个客户端)。我知道我可以使用Akka的
路由器
功能,但这不是我目前的问题。问题是我必须存储所有活动客户端的列表。现在我将它存储在
WebSocketRouter
类的静态列表中。这是编写概念验证原型的最快方式,但它不是线程安全的,而且似乎不是“Akka方式”。 下面是一个简化的代码示例:

WebSocketController:

//This controller handles the creation of WebSockets.
public class WebSocketController extends Controller {
    public static WebSocket<String> index() {
        return WebSocket.withActor(new F.Function<ActorRef, Props>() {
            public Props apply(ActorRef out) throws Throwable {
                return MessageSender.props(out);
            }
        });
    }
}
//Hold a reference to the auto-created Actor that handles WebSockets 
//and also registers and unregisters itself in the router.
public class  MessageSender extends UntypedActor {

    public static Props props(ActorRef out) {
        return Props.create(MessageSender.class, out);
    }

    private final ActorRef out;

    public MessageSender(ActorRef out) {
        this.out = out;
    }

    @Override
    public void preStart() {
        WebSocketRouter.addSender(getSelf());
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            out.tell(message, getSelf());
        }
        else {
            unhandled(message);
        }
    }

    public void postStop() {
        WebSocketRouter.removeSender(getSelf());
    }
}
public class WebSocketRouter extends UntypedActor {
    private static ArrayList<ActorRef> senders;
    static {
        senders = new ArrayList<>();
    }

    public static void addSender(ActorRef actorRef){
        senders.add(actorRef);
    }

    public static void removeSender(ActorRef actorRef){
        senders.remove(actorRef);
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            for (ActorRef sender : senders) {
                sender.tell(message, getSelf());
            }
        }
    }
}
WebSocketOuter:

//This controller handles the creation of WebSockets.
public class WebSocketController extends Controller {
    public static WebSocket<String> index() {
        return WebSocket.withActor(new F.Function<ActorRef, Props>() {
            public Props apply(ActorRef out) throws Throwable {
                return MessageSender.props(out);
            }
        });
    }
}
//Hold a reference to the auto-created Actor that handles WebSockets 
//and also registers and unregisters itself in the router.
public class  MessageSender extends UntypedActor {

    public static Props props(ActorRef out) {
        return Props.create(MessageSender.class, out);
    }

    private final ActorRef out;

    public MessageSender(ActorRef out) {
        this.out = out;
    }

    @Override
    public void preStart() {
        WebSocketRouter.addSender(getSelf());
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            out.tell(message, getSelf());
        }
        else {
            unhandled(message);
        }
    }

    public void postStop() {
        WebSocketRouter.removeSender(getSelf());
    }
}
public class WebSocketRouter extends UntypedActor {
    private static ArrayList<ActorRef> senders;
    static {
        senders = new ArrayList<>();
    }

    public static void addSender(ActorRef actorRef){
        senders.add(actorRef);
    }

    public static void removeSender(ActorRef actorRef){
        senders.remove(actorRef);
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            for (ActorRef sender : senders) {
                sender.tell(message, getSelf());
            }
        }
    }
}
公共类WebSocketOuter扩展了非类型转换器{
私有静态ArrayList发送器;
静止的{
senders=newarraylist();
}
公共静态void addSender(ActorRef ActorRef){
发件人。添加(actorRef);
}
公共静态无效移除器(ActorRef ActorRef){
发件人。删除(actorRef);
}
@凌驾
public void onReceive(对象消息)引发异常{
if(字符串的消息实例){
对于(ActorRef发送方:发送方){
sender.tell(message,getSelf());
}
}
}
}
再一次,我知道这是一个糟糕的解决方案,我正在寻找一个更好的解决方案。我曾经考虑过创建一个线程安全的单例类来保存当前的连接。我还考虑将当前连接列表保存在某个Akka actor的实例中,并通过Akka消息修改该列表,但为了实现这一目的,我必须静态地将
ActorRef
存储到该actor,以便可以从不同的
ActorSystem
访问该列表


解决我的问题最适合阿克卡意识形态的最佳方法是什么?

与其静态引用一个演员(
WebSocketRouter
),为什么不想出一些消息来发送呢?这样,参与者就可以以一致的方式保持自己的内部状态。通过消息进行状态更改是Actor模型的主要优点之一

在我开始编写代码之前,如果这不是100%准确的话,我很抱歉,我只使用了Akka的Scala版本,我是基于对

所以在你的例子中,我会定义一些对象来表示加入/离开

public class JoinMessage { } 
public class ExitMessage { } 
请注意,
ExitMessage
只有在您打算保持WebSocket打开并让用户停止监听路由器时才真正需要。否则,路由器可以检测参与者何时被终止

然后,您可以更改您的
MessageSender
actor,以便在他们加入或离开聊天室时发送这些消息

public class MessageSender extends UntypedActor {

    public static Props props(ActorRef out) {
        return Props.create(MessageSender.class, out);
    }

    private final ActorRef out;
    private final ActorRef router;

    public MessageSender(ActorRef out) {
        this.out = out;
        this.router= getContext().actorSelection("/Path/To/WebSocketRouter");
    }

    @Override
    public void preStart() {
        router.tell(new JoinMessage(), getSelf());
    }

    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            out.tell(message, getSelf());
        } else {
            unhandled(message);
        }
    }    
}
然后,您的路由器可以更改为在内部管理状态,而不是在参与者上公开内部方法(您知道这是不好的)

公共类WebSocketOuter扩展了非类型转换器{
私有最终集发送者=新HashSet();
私有void addSender(ActorRef ActorRef){
发件人。添加(actorRef);
}
专用无效删除器(ActorRef ActorRef){
发件人。删除(actorRef);
}
@凌驾
public void onReceive(对象消息)引发异常{
if(JoinMessage的消息实例){
addSender(发送方);
getContext().watch(sender);//监视sender,以便我们可以检测它们何时死亡。
}else if(消息instanceof Terminated){
//我们监视的一个发送者死了。
移除器(发送器);
}else if(字符串的消息实例){
对于(ActorRef发送方:发送方){
sender.tell(message,getSelf());
}
}
}
}

同样,这段代码是为了让您了解如何利用Actor模型来完成这项任务。抱歉,如果Java不是100%准确的,但希望您能遵循我的意图。

谢谢您的回答。这和我自己做的差不多。对我来说,一个巨大的问题是,我必须使用
WebSocketRouter
的一个实例,并且我必须能够从不同的
ActorSystem
访问这个对象。我在默认的Akka
ActorSystem
中创建了它,并通过它的
路径在整个代码中访问它。我有一个愚蠢的问题,我刚从WebSocket&actors开始。在最基本的示例中,控制器中有一个返回websocket的方法,使用
websocket.tryAcceptWithActor
Props
。如何向参与者发送消息(任意-非响应)!?我有对websocket的引用,但没有看到任何要编写、发送或获取演员的内容…嘿,当我尝试停止演员时,websocket连接将关闭,并且不会再次打开,如果你有任何想法,请让我知道