java如何在Play framework 2应用程序中存储Akka参与者列表?
我有一个Play framework 2应用程序,它可以接收数据并通过WebSocket将数据发送给多个客户端。我使用Akka演员处理WebSocket,就像在this documentation中一样。我还有一个WebSocketRouter
类,它扩展了UntypedActor
并包含路由逻辑(决定将系统接收到的数据传递给哪个客户端)。我知道我可以使用Akka的Router
功能,但这不是我目前的问题。问题是我必须存储所有活动客户端的列表。现在我将它存储在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);
}
});
}
}
MessageSender:
//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());
}
}
WebSocketOuter:
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());
}
}
}
}
再一次,我知道这是一个糟糕的解决方案,我正在寻找一个更好的解决方案。我曾经考虑过创建一个线程安全的单例类来保存当前的连接。我还考虑将当前连接列表保存在某个Akka参与者的实例中,并通过Akka消息修改该列表,但为了实现这一目的,我必须静态地存储一个到该参与者的ActorRef
,以便可以从不同的ActorSystem
访问它
什么是解决我的问题的最好方法,最适合阿克卡意识形态
# 1 楼答案
与其对参与者进行静态引用(
WebSocketRouter
),为什么不想出一些消息来发送它呢?这样,参与者就可以以一致的方式保持自己的内部状态。通过消息进行状态更改是Actor模型的主要优点之一在我开始编写代码之前,如果这不是100%准确的话,我很抱歉,我只使用了Akka的Scala版本,并且基于对Akka Documentation的快速扫描
所以在你的例子中,我会定义一些对象来表示加入/离开
请注意
ExitMessage
仅在您打算保持WebSocket打开并让用户停止侦听路由器时才真正需要。否则,路由器可以检测参与者何时被终止然后,您可以更改您的
MessageSender
参与者,以便在他们加入或离开聊天室时发送这些消息然后,您的路由器可以更改为在内部管理状态,而不是在参与者上公开内部方法(您知道这是不好的)
同样,这段代码是为了让您了解如何利用Actor模型来完成这项任务。如果Java不是100%准确的话,很抱歉,但希望您能遵循我的意图