Spring ServletContext
を検索してBeanを検索するには、@ServerEndpoint
内からApplicationContext
を取得する必要があります。
現時点では、最善の方法は、そのBeanをJNDIネーミングコンテキストにバインドし、Endpoint
でルックアップすることです。より良い解決策があれば歓迎します。
また、サーブレットのHttpSession
をwebsocketのSession
と同期するための適切な方法も探しています。
サーブレットHttpSession
はJSR-356にあります HandshakeRequest#getHttpSession()
によって利用可能です @OnOpen
の直前にハンドシェイク要求が行われると利用可能になります @ServerEndpoint
のServletContext
は HttpSession#getServletContext()
を介して使用できます。それは一石二鳥です。
ハンドシェイク要求をキャプチャするには、 ServerEndpointConfig.Configurator
を実装し、 modifyHandshake()
メソッドをオーバーライドします。 HandshakeRequest
は、ここでメソッド引数として使用できます。 HttpSession
を EndpointConfig#getUserProperties()
に入れることができます。 EndpointConfig
は、メソッドの引数 @OnOpen
として使用できます。
ServerEndpointConfig.Configurator
実装のキックオフの例を次に示します。
public class ServletAwareConfig extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put("httpSession", httpSession);
}
}
これを使用する方法は次のとおりです。@ServerEndpoint
の configurator
属性に注意してください。
@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
@OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
@OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
設計のヒントとして、@ServerEndpoint
をサーブレットAPIの依存関係から完全に解放することをお勧めします。 modifyHandshake()
実装では、サーブレットセッションまたはコンテキストから必要な正確なthat情報(通常は変更可能なJavabean)をすぐに抽出し、代わりにユーザープロパティマップに配置します。これを行わない場合は、WebSocketセッションがHTTPセッションよりも長く存続できることに注意してください。したがって、エンドポイントにHttpSession
を持ち歩いている場合、期限切れになっているときにアクセスしようとすると、IllegalStateException
に遭遇する可能性があります。
CDI(およびおそらくJSF)を手元に置いている場合、 OmniFaces <o:socket>
(リンクはショーケースの一番下にあります)のソースコードからインスピレーションを得ます。
BalusCの回答のコードを更新しました。onOpenメソッドは@OnOpenで装飾する必要があります。その後、Endpointクラスを拡張する必要はもうありません。
@ServerEndpoint(value="/your_socket", configurator=ServletAwareConfig.class)
public class YourSocket {
private EndpointConfig config;
@OnOpen
public void onOpen(Session websocketSession, EndpointConfig config) {
this.config = config;
}
@OnMessage
public void onMessage(String message) {
HttpSession httpSession = (HttpSession) config.getUserProperties().get("httpSession");
ServletContext servletContext = httpSession.getServletContext();
// ...
}
}
BalusCの上記session
ではServletAwareConfig
を取得できない場合があります。これは、セッションがまだ作成されていないためです。セッションではなくservletContextを探すので、Tomcatでは次のようにできます。
public static class ServletAwareConfig extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
try {
Field reqfld = request.getClass().getDeclaredField("request");
reqfld.setAccessible(true);
HttpServletRequest req = (HttpServletRequest) reqfld.get(request);
ServletContext ctxt = req.getServletContext();
Map<String, Object> up = config.getUserProperties();
up.put("servletContext", ctxt);
} catch (NoSuchFieldException e) {
} catch (SecurityException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
}
}
すぐに初期化セッションが必要な場合は、request.getSession()を呼び出すことができます。
Tomcat(バージョン7.0.56および8.0.14)でBalusCの回答を試しました。両方のコンテナで、modifyHandshakeのリクエストパラメータにはHttpSessionが含まれていません(したがって、servletContextは含まれていません)。 「グローバル」変数(Webアプリケーショングローバル)にアクセスするためだけにサーブレットコンテキストが必要だったので、これらの変数をホルダークラスの通常の静的フィールドに格納しました。これはエレガントではありませんが、うまくいきました。
これは、この特定のTomcatバージョンのバグのように見えます-これを見た人はいますか?