Tomcat WebSocketServlet和Google Guice

时间:2012-12-19 17:48:30

标签: java servlets websocket tomcat7 guice

我有一个需要使用Tomcat 7网络套接字的webapp。

在此网络应用程序中,所有标准Servlet(扩展javax.servlet.http.HttpServlet)都可以很好地(并且正确地)与 Google Guice 一起使用。为了使我的Servlet与Guice处理程序一起使用,我只需:

  1. 使用@Singleton
  2. 装饰servlet
  3. Provider实例& amp;声明私有MyHandler生成一个标记为注射的setter
  4. @Inject
  5. 装饰Servlet的构造函数

    示例以证明以上几点:

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

    如何从WebSocketServlet调用同一个Guice处理程序,上面称为myHandler

    我不能采用与标准servlet用例相同的样式,因为不是像标准servlet那样拥有Singleton servlet,每个WebSocket通信都会产生一个扩展MessageInbound的实例;然后从MessageInbound实例中的方法(例如MyHandleronOpen)调用调用onClose的适当方法; 来自HttpServlet个实例中的方法{/ 1}}。

    我尝试了什么?我尝试了一些(概念上错误的)解决方案,例如从MyServlet实例中调用websocket-servlet的处理程序;这当然会导致范围问题降低Guice堆栈跟踪。这样做的概念正确方式是什么?

2 个答案:

答案 0 :(得分:1)

查看GitHub示例后更新:

你如何使用Guice就好了。由于MessageInbound只有一个特定的用法,因此不需要任何与AbstractGuiceWebSocketServlet一样的糖。提供者chatLogHdlr然后做手动构建就可以了。但是你失去了AOP的支持。如果需要,您可能需要执行Assisted Inject。但是现在这很好。

另一方面,使用施工注射而不是二次注射。

我立即看到了什么问题。 这不是Guice,而是你如何使用Guice-Persist。我没有经常使用GP,仍然使用古老的Warp-persist。但是我在你的代码中看到了如何使用Guice-persist的两个问题:

  1. 您需要注入PersistService才能启动Guice-Persist。它在WIKI例如

    中进行了解释
    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. PersistFilter没有用,因为只有WebSocket第一次通过过滤器,但所有后续通信都不会通过过滤器。在@Transactional(每次交易会话)周围使用txn是可行的方法。

  3. 题外话:

    您打算支持多少用户?如果这将是一个硬核聊天服务器,我会使用Netty,但它更多涉及。谷歌搜索发现了这个:

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

    原始答案:

    所以这是关于风格的问题?

    WebSockets!= Servlets。如果它们需要稍微不同的风格,那就没有错。我甚至更愿意提醒我不要处理香草小服务。

    一些观察结果:

    WebSocketServlet没什么特别的。您可以轻松地将它与Guice-Servlet一起使用。 E.g:

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

    然后将其称为

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

    现在,MessageInbound是特别的,因为Tomcat正如您所解释的那样处理。 MessageInbound是WebSocket作用域。现在Guice对这个范围一无所知,将它留在那里可能是有意义的。

    对于初学者,我确保MessageInbound是由Guice创建的。这方面的事情:

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

    您可以根据需要从此处转到更高的抽象和/或搜索范围。我并不特别喜欢#getWsOutbound()因为它阻碍了测试。

    在你满意之前,不断改进风格。如果您需要更多帮助(将修改答案),请说明。

答案 1 :(得分:0)

我并不完全明白你想要完成的事情。我会在Guice寻找AOP支持。在使用MessageInbound子类的某些方法之前,似乎需要设置MyHandler(注入)。实例。一个方面可以做到这一点。

但是,您需要问一个问题:(实体化)控制在哪里?如果有某种方法可以在Tomcat应用程序配置中添加某种委托,Guice可以“增强”#34; MessageInbound实例,在使用之前,它将具有正确的MyHandler设置。