java - nfl - Tomcat WebSocketServlet y Google Guice
guice provides (2)
Actualiza después de mirar el ejemplo de GitHub:
Cómo usas a Guice está bien. Como solo hay un uso particular de MessageInbound, no es necesario ningún azúcar como el AbstractGuiceWebSocketServlet. El proveedor chatLogHdlr y luego realizar la construcción manual está bien. Pero pierdes soporte de AOP. Si es necesario, es posible que desee hacer Inyección asistida. Pero por ahora esto está bien.
En una nota al margen, use inyección de construcción en lugar de inyección setter.
Vi de inmediato cuál es el problema. No es Guice sino cómo usas Guice-Persist. No usé GP mucho y sigo usando el venerable Warp-persist. Pero veo 2 problemas con la forma en que usas Guice-persist en tu código:
Necesita inyectar el servicio Persist para iniciar Guice-Persist. Se explica en el WIKI por ejemplo
public class PocWebApp extends GuiceServletContextListener { @Inject PersistService ps; @Override protected Injector getInjector() { Injector injector = Guice.createInjector(new ServletModule() { @Override protected void configureServlets() { install(new JpaPersistModule("DesktopPU")); serve("/socket/main/").with(MainSocket.class); } }); injector.injectMembers(this); return injector; } @Override public void contextInitialized(ServletContextEvent servletContextEvent) { super.contextInitialized(servletContextEvent); ps.start(); } }
PersistFilter es inútil, ya que solo la primera vez que WebSocket pasará a través del filtro, pero todas las comunicaciones subsiguientes no pasarán por el filtro. Usar el txn justo alrededor de @Transactional (Session-per-transaction) es el camino a seguir.
Fuera de contexto:
¿Cuántos usuarios pretendes apoyar? Si este va a ser un servidor de chat hardcore, utilizaría Netty en su lugar, pero es algo más complicado. Google encontró esto:
http://comoyo.github.com/blog/2012/07/30/integrating-websockets-in-netty/
Respuesta original:
¿Entonces esta es una pregunta sobre el estilo?
WebSockets! = Servlets. No hay nada de malo si requieren un estilo ligeramente diferente. Prefiero que me recuerden que no estoy tratando con servlets de vainilla.
Algunas observaciones:
WebSocketServlet no es nada especial. Puedes usarlo fácilmente con Guice-Servlet. P.ej:
@Singleton
public class FooGuiceWebSocketServlet extends WebSocketServlet {...}
Y luego lo refieren como
serve("/foo").with(FooGuiceWebSocketServlet.class);
Ahora, MessageInbound es especial ya que todo lo maneja Tomcat como explicaste. El MessageInbound tiene un alcance de WebSocket. Ahora, Guice no tiene idea de este alcance y podría tener sentido dejarlo así.
Para empezar, me aseguraré de que MessageInbound sea creado por Guice. Algo en esta línea:
@Singleton
public class ExampleWebSocketServlet extends AbstractGuiceWebSocketServlet {
@Override
public Class<? extends StreamInbound> serveWith() {
return Foo.class;
}
public static class Foo extends MessageInbound {
@Inject GuiceCreatedAndInjected bar;
@Override
protected void onBinaryMessage(ByteBuffer byteBuffer) throws IOException {
// do nothing
}
@Override
protected void onTextMessage(CharBuffer charBuffer) throws IOException {
// this getSwOutbonds() is not very friendly to testing
getWsOutbound().writeTextMessage(bar.echo(charBuffer));
}
}
}
Dónde
public abstract class AbstractGuiceWebSocketServlet extends WebSocketServlet {
@Inject Injector injector;
@Override
protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) {
return injector.getInstance(serveWith());
}
public abstract Class<? extends StreamInbound> serveWith();
}
Puede ir desde aquí a abstracciones más altas y / o scopings según sea necesario. No me gusta especialmente MessageInbound ya que dificulta las pruebas.
Solo sigue mejorando el estilo hasta que estés satisfecho. Di si necesitas más ayuda (modificará la respuesta).
Tengo una aplicación web que requiere el uso de los sockets web Tomcat 7.
En esta aplicación web, todos los servlets estándar (aquellos que extienden javax.servlet.http.HttpServlet
) funcionan bien (y correctamente) con Google Guice . Para que mi Servlet funcione con los controladores de Guice, simplemente:
- decorar el servlet con
@Singleton
- declarar el
Provider
privado para la instanciaMyHandler
y generar un setter que está marcado para inyección - decorar el constructor de Servlet con
@Inject
Ejemplo para demostrar los puntos anteriores:
@Singleton
public class MyServlet extends HttpServlet {
private Provider<MyHandler> myHandler;
@Inject
MyServlet() {
}
@Override
protected void service(..) throws ServletException { ... }
@Inject
public void setMyHandler(Provider<MyHandler> myHandler) {
this.myHandler = myHandler;
}
...
}
¿Cómo se puede llamar al mismo manejador de Guice, anteriormente llamado myHandler
desde un WebSocketServlet
?
No puedo adoptar el mismo estilo que en el caso de uso de servlet estándar porque, en lugar de tener un servlet de Singleton como en el caso de los servlets estándar, cada comunicación de WebSocket da como resultado una instancia que extiende MessageInbound
; a continuación, se llama al método apropiado que llamaría MyHandler
desde un método (por ejemplo, onOpen
o onClose
) dentro de la instancia de MessageInbound; no desde un método dentro de una instancia de MyServlet
como MyServlet
arriba.
¿Qué probé? Intenté algunas soluciones (conceptualmente incorrectas) como llamar a los manejadores de websocket-servlet desde dentro de la instancia de MessageInbound
; eso, por supuesto, da como resultado problemas de alcance más abajo en la traza de pila de Guice. ¿Cuál es la forma conceptualmente correcta de hacer esto?
No entendí exactamente lo que estás tratando de lograr. Buscaría apoyo de AOP en Guice. Parece que necesita que MyHandler esté configurado (inyectar) antes de ser utilizado en algunos métodos de la instancia de la subclase MessageInbound. Un aspecto podría hacer eso.
Sin embargo, hay una pregunta que debe hacerse: ¿dónde está el control (de la instauración)? Si hay alguna manera de agregar algún tipo de delegación en la configuración de su aplicación Tomcat, Guice podría "mejorar" las instancias de MessageInbound que, a su vez, tendrían el conjunto adecuado de MyHandler antes de su uso.