Tomcat WebSocketServlet和Google Guice

Jos*_*mit 27 java servlets guice websocket tomcat7

我有一个webapp,需要使用Tomcat 7 Web套接字.

在这个webapp中,所有标准的Servlet(扩展的javax.servlet.http.HttpServlet)都能很好地(和正确地)与Google Guice一起工作.为了让我的Servlet与Guice处理程序一起使用,我只需:

  1. 用它装饰servlet @Singleton
  2. 声明私有ProviderMyHandler例如&产生被标记为注入一个setter
  3. 用它来装饰Servlet的构造函数 @Inject

举例说明以上几点:

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

    ...
}
Run Code Online (Sandbox Code Playgroud)

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

我不能采用与标准servlet用例相同的样式,因为不是像标准servlet那样拥有Singleton servlet,每个WebSocket通信都会导致实例扩展MessageInbound; 然后MyHandler从MessageInbound实例中的方法(例如onOpenonClose)调用将调用的适当方法; 不是来自上述HttpServlet实例中的方法MyServlet.

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

Ale*_*čko 1

查看 GitHub 示例后更新:

你如何使用 Guice 就可以了。由于 MessageInbound 只有一种特定用法,因此不需要像 AbstractGuiceWebSocketServlet 那样的任何糖。提供chatLogHdlr然后手动构建就可以了。但是你失去了 AOP 支持。如果需要,您可能需要进行辅助注射。但目前来说这还好。

顺便说一句,使用构造注入而不是设置器注入。

我立即看出问题所在。这不是 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();
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. PersistFilter 是无用的,因为只有第一次 WebSocket 才会通过过滤器,但所有后续通信都不会通过过滤器。在@Transactional(每笔交易会话)周围使用txn是正确的方法。

无关:

您打算支持多少用户?如果这将成为一个硬核聊天服务器,我会使用 Netty,但它有点复杂。谷歌搜索发现了这个:

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

原答案:

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

WebSocket != Servlet。如果他们需要稍微不同的风格,也没有什么问题。我什至更希望有人提醒我我不是在处理普通的 servlet。

一些观察结果:

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

 @Singleton
 public class FooGuiceWebSocketServlet extends WebSocketServlet {...}
Run Code Online (Sandbox Code Playgroud)

然后将其引用为

 serve("/foo").with(FooGuiceWebSocketServlet.class);
Run Code Online (Sandbox Code Playgroud)

现在,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));
    }

   }
}
Run Code Online (Sandbox Code Playgroud)

在哪里

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

}
Run Code Online (Sandbox Code Playgroud)

您可以根据需要从这里转到更高的抽象和/或范围。我不太喜欢#getWsOutbound(),因为它阻碍了测试。

不断改进风格,直到您满意为止。说出您是否需要更多帮助(将修改答案)。