27 votes

Tomcat WebSocketServlet et Google Guice

J'ai une application web qui nécessite l'utilisation de Tomcat 7 les web sockets.

Dans cette webapp tous les types de Servlets (ceux qui s'étendent javax.servlet.http.HttpServlet) fonctionnent bien (et correctement) avec Google Guice. Pour faire ma Servlet travailler avec Guice gestionnaires j'ai tout simplement:

  1. décorer la servlet avec @Singleton
  2. déclarer privé Provider pour MyHandler exemple & de générer un setter qui est marqué pour injection
  3. décorer la Servlet constructeur @Inject

Exemple pour démontrer les points ci-dessus:

@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;
    }

    ...
}

Comment peut-on appeler le même Guice gestionnaire, ci-dessus intitulée myHandler d'un WebSocketServlet?

Je ne peux pas adopter le même style que dans la norme servlet cas d'utilisation parce que, plutôt que d'avoir un Singleton servlet comme dans le cas de la norme de servlets, chaque WebSocket la communication des résultats d'une instance d'étendre MessageInbound; ensuite, la méthode appropriée qui permettrait d'attirer MyHandler est appelée à partir d'une méthode (par exemple, onOpen ou onClose) au sein de la MessageInbound instance; pas à partir d'une méthode à l'intérieur d'un HttpServlet de l'instance en tant que MyServlet - dessus.

Qu'ai-je essayer? Je l'ai fait essayer certains (conceptuellement mal) des solutions telles que l'appel de la websocket-servlet gestionnaires au sein de l' MessageInbound de l'instance; que, bien sûr, les résultats dans la portée des problèmes en bas de l'Guice trace de la pile. Qu'est-ce que le plan conceptuel de correcte manière de procéder?

1voto

Alen Vrečko Points 382

Mise à jour après avoir regardé GitHub exemple:

La façon dont vous utilisez Guice est tout simplement parfait. Depuis, il ya juste un particulier de l'utilisation de MessageInbound de sucre, comme avec le AbstractGuiceWebSocketServlet est inutile. Fournisseur de chatLogHdlr et ensuite de faire de manuel de construction est OK. Mais vous perdez de l'AOP de soutien. Si cela est nécessaire, vous pouvez faire Assistée Injecter. Mais pour l'instant c'est très bien.

Sur une note de côté, l'utilisation de la construction d'injection au lieu de l'injection par mutateur.

J'ai vu tout de suite ce qui est le problème. Il n'est pas Guice, mais plutôt de la façon dont vous utilisez Guice-Persistent. Je n'ai pas utilisé de GP beaucoup et encore utiliser le vénérable Chaîne, persistent. Mais je vois 2 problèmes avec la façon dont vous utilisez Guice-persister dans votre code:

  1. Vous avez besoin d'injecter de l'PersistService pour commencer Guice-Persistent. Il est expliqué dans le WIKI par exemple

    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();
    }
    }
    
  2. Le PersistFilter est inutile que seulement la première fois WebSocket va à travers le filtre, mais toutes les communications ne passent par le filtre. À l'aide de la txn juste autour de @Transactionnelle (Session-par-transaction) est le chemin à parcourir.

Hors-sujet:

Combien d'utilisateurs avez-vous l'intention de les soutenir? Si cela va être un hardcore serveur de chat je ne l'utiliserais Netty à la place, mais il est un peu plus compliqué. Googler trouvé ceci:

http://comoyo.github.com/blog/2012/07/30/integrating-websockets-in-netty/

Réponse originale à cette question:

Donc, c'est une question de style?

Les WebSockets != Les Servlets. Il n'y a rien de mal s'ils ont besoin d'un style un peu différent. J'avais même préférez être rappelé, je ne suis pas traiter avec de la vanille de servlets.

Quelques observations:

WebSocketServlet est rien de spécial. Vous pouvez facilement l'utiliser avec Guice-Servlet. E. g.:

 @Singleton
 public class FooGuiceWebSocketServlet extends WebSocketServlet {...}

Et puis refernce comme

 serve("/foo").with(FooGuiceWebSocketServlet.class);

Maintenant, MessageInbound qui est spécial car tout est géré par Tomcat comme vous l'avez expliqué. Le MessageInbound est WebSocket étendue. Maintenant Guice a aucune idée de ce champ d'application, et il pourrait être bon de laisser de cette façon.

Pour commencer, je m'assurerais MessageInbound est créé par Guice. Quelque chose le long de ces lignes:

@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));
    }

   }
}

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();

}

Vous pouvez aller à partir d'ici au plus hautes abstractions et/ou scopings en tant que de besoin. Je n'aime pas particulièrement les #getWsOutbound() que c'est une entrave à l'essai.

Il suffit de garder sur l'amélioration du style jusqu'à ce que vous êtes satisfait. Dire si vous avez besoin de plus d'aide (va modifier la réponse).

0voto

Robson França Points 453

Je n'ai pas très bien comprendre ce que vous essayez d'accomplir. Je veux le regarder pour l'AOP soutien dans Guice. Il semble que vous avez besoin que MyHandler est défini (injecter) avant d'être utilisé dans certaines méthodes de MessageInbound sous-classe' instance. Un aspect pourrait le faire.

Cependant, il ya une seule question que vous devez vous poser: où est l' (instantialization) contrôle? S'il existe un moyen d'ajouter une sorte de délégation dans votre Tomcat de configuration de l'application, Guice pourrait "améliorer" le MessageInbound instances qui, à son tour, aurait la bonne MyHandler avant de les utiliser.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X