慕村9548890
Configurator可以同时由多个线程调用,很可能您无法在来自modifyHandshake()和的调用之间访问正确的HttpSession对象getEndpointInstance()。或者说另一种方式......请求A.修改握手A.请求B.修改握手B.获取端点实例A < - 这将具有请求B的HttpSession获取端点实例B.这是对Martin的代码的修改,它使用ServerEndpointConfig.getUserProperties()map HttpSession在@OnOpen方法调用期间使套接字实例可用GetHttpSessionConfigurator.javapackage examples;import javax.servlet.http.HttpSession;import javax.websocket.HandshakeResponse;import javax.websocket.server.HandshakeRequest;import javax.websocket.server.ServerEndpointConfig;public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator{ @Override public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { HttpSession httpSession = (HttpSession)request.getHttpSession(); config.getUserProperties().put(HttpSession.class.getName(),httpSession); }}GetHttpSessionSocket.javapackage examples;import java.io.IOException;import javax.servlet.http.HttpSession;import javax.websocket.EndpointConfig;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;@ServerEndpoint(value = "/example", configurator = GetHttpSessionConfigurator.class)public class GetHttpSessionSocket{ private Session wsSession; private HttpSession httpSession; @OnOpen public void open(Session session, EndpointConfig config) { this.wsSession = session; this.httpSession = (HttpSession) config.getUserProperties() .get(HttpSession.class.getName()); } @OnMessage public void echo(String msg) throws IOException { wsSession.getBasicRemote().sendText(msg); }}额外功能:不需要instanceof或需要铸造。一些EndpointConfig知识EndpointConfig 每个“端点实例”都存在对象。但是,“端点实例”与规范有2个含义。JSR的默认行为,其中每个传入的升级请求都会生成端点类的新对象实例javax.websocket.Session将对象端点实例及其配置连接到特定逻辑连接的A。可以将单个端点实例用于多个javax.websocket.Session实例(这是ServerEndpointConfig.Configurator支持的功能之一)ServerContainer实现将跟踪一组ServerEndpointConfig,它们代表服务器可以响应websocket升级请求的所有已部署端点。这些ServerEndpointConfig对象实例可以来自几个不同的来源。手动提供的 javax.websocket.server.ServerContainer.addEndpoint(ServerEndpointConfig)通常在javax.servlet.ServletContextInitializer.contextInitialized(ServletContextEvent sce)通话中完成来自javax.websocket.server.ServerApplicationConfig.getEndpointConfigs(Set)电话。通过扫描Web应用程序为@ServerEndpoint注释类自动创建。这些ServerEndpointConfig对象实例作为javax.websocket.Session最终创建时的默认值存在。ServerEndpointConfig.Configurator实例在收到或处理任何升级请求之前,所有ServerEndpointConfig.Configurator对象现在都已存在并准备好执行其主要和唯一目的,以允许自定义websocket连接的升级过程到最终javax.websocket.Session访问特定于会话的EndpointConfig请注意,您无法ServerEndpointConfig从端点实例中访问对象实例。您只能访问EndpointConfig实例。这意味着如果您ServerContainer.addEndpoint(new MyCustomServerEndpointConfig())在部署期间提供并稍后尝试通过注释访问它,则它将无法工作。以下所有内容均无效。@OnOpenpublic void onOpen(Session session, EndpointConfig config){ MyCustomServerEndpointConfig myconfig = (MyCustomServerEndpointConfig) config; /* this would fail as the config is cannot be cast around like that */}// --- or ---@OnOpenpublic void onOpen(Session session, ServerEndpointConfig config){ /* For @OnOpen, the websocket implementation would assume that the ServerEndpointConfig to be a declared PathParam */}// --- or ---@OnOpenpublic void onOpen(Session session, MyCustomServerEndpointConfig config){ /* Again, for @OnOpen, the websocket implementation would assume that the MyCustomServerEndpointConfig to be a declared PathParam */}您可以在Endpoint对象实例的生命周期内访问EndpointConfig,但是在有限的时间内。的javax.websocket.Endpoint.onOpen(Session,Endpoint),带有注释的@OnOpen方法,或通过使用CDI的。EndpointConfig不以任何其他方式或任何其他时间提供。但是,您始终可以通过Session.getUserProperties()呼叫访问UserProperties,该呼叫始终可用。此用户属性地图总是可用的,通过注释的技术(如在会话期间的参数是它@OnOpen,@OnClose,@OnError,或@OnMessage呼叫),通过CDI注射会话的,或者即使使用,从延长非注释的WebSockets的javax.websocket.Endpoint。升级如何运作如前所述,每个定义的端点都将ServerEndpointConfig与之关联。这些ServerEndpointConfigs是单个实例,表示EndpointConfig最终可用于最终创建的端点实例的默认状态。当传入的升级请求到达时,它已在JSR上执行以下操作。路径是否与任何ServerEndpointConfig.getPath()条目匹配如果不匹配,则返回404进行升级将升级请求传递到ServerEndpointConfig.Configurator.checkOrigin()如果无效,则返回错误以升级响应创建HandshakeResponse将升级请求传递到ServerEndpointConfig.Configurator.getNegotiatedSubprotocol()在HandshakeResponse中存储答案将升级请求传递到ServerEndpointConfig.Configurator.getNegotiatedExtensions()在HandshakeResponse中存储答案创建新的端点特定的ServerEndpointConfig对象。复制编码器,解码器和用户属性。这个新的ServerEndpointConfig包含路径,扩展,端点类,子协议,配置器的默认值。将升级请求,响应和新的ServerEndpointConfig传递到ServerEndpointConfig.Configurator.modifyHandshake()调用ServerEndpointConfig.getEndpointClass()在ServerEndpointConfig.Configurator.getEndpointInstance(Class)上使用class创建Session,关联端点实例和EndpointConfig对象。通知连接的端点实例需要EndpointConfig的带注释的方法获取与此Session关联的方法。调用Session.getUserProperties()返回EndpointConfig.getUserProperties()需要注意的是,ServerEndpointConfig.Configurator是每个映射的ServerContainer端点的单例。这是有意的,并且是期望的,以允许实现者具有若干特征。如果他们愿意,为多个对等体返回相同的Endpoint实例。所谓无状态的websocket写作方法。为所有Endpoint实例提供昂贵资源的单点管理如果实现为每次握手创建了新的Configurator,则该技术将无法实现。