这里有三个解决方案。他们可能无法帮助使用 Glassfish 的原始海报;我不知道。但它们是已发布问题的答案,可能会有一些用处。
我为我的服务器使用嵌入式 Jetty。(这意味着服务器是在我的 Java 代码中创建的,所以我可以访问所有内容。)
答案 1:让您的 websocket 服务器端点监听从您的主线程发送的 CDI 事件。我没有这样做,但我认为这是一个非常干净的概念。
答案 2:让您的端点在主线程中“注册”自身。
在核心类中创建一个静态集合成员:
public class Core()
...
public static List<MyEndpoint> webSockets = new ArrayList<MyEndpoint>();
Endpoint 将 self 添加到集合中:
@ServerEndpoint(value="/path/")
public class MyEndpoint
{
@OnOpen
public void onWebSocketConnect(javax.websocket.Session session)
{
synchronized(Core.webSockets)
{
Core.webSockets.add(this);
}
...
}
回到 Core,您将遍历webSockets
以发送消息。同步迭代,或者更好的是,复制webSockets
并迭代整个副本(标准同步收集实践)。您还需要在@OnClose 中处理从列表中的删除,并在迭代期间注意关闭的套接字。
请注意,可以根据需要以其他方式完成同步:Collections.synchronizedList() 或 CopyOnWriteArrayList 在不同情况下很有用。
答案 3:控制构建端点实例。这是我的选择中最强大的,因为您可以使用数据和外部引用来构建它。
我的实现是基于 JSR-356(和 Jetty)的,但其他框架中也有钩子。总是略显复杂。
在服务器创建期间:
context = new ServletContextHandler(ServletContextHandler.SESSIONS);
// ... more server creation
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
wscontainer.addEndpoint(ServerEndpointConfig.Builder.create(MyEndpoint.class, "/path/")
.configurator(new MyConfigurator(aSocketManagerObject))
.build());
在哪里:
public class MyConfigurator extends javax.websocket.server.ServerEndpointConfig.Configurator
{
private final ManagerObject aSocketManagerObject;
public EventsConfigurator(ManagerObject aSocketManagerObject)
{
this.aSocketManagerObject = aSocketManagerObject;
}
@Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
{
return (T) new MyEndpoint(aSocketManagerObject); // This constructor to be added to your MyEndpoint class
}
}
端点现在有一个引用aSocketManagerObject
并且可以自由地与它通信以获取数据、注册为侦听器等。
Bhaskar S. 在Introduction to WebSockets中提供了答案 3 的健壮实现
编辑:
有关 CDI 方法的更多信息是有问题的,如何获取现有的 websocket 实例。
并且从 Web Socket @ServerEndpoint 中的 HttpServletRequest 访问 HttpSession包括关于端点实例的长时间讨论。