27

我有一个需要使用 Tomcat 7 Web 套接字的 Web 应用程序。

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

  1. 装饰 servlet@Singleton
  2. Provider例如声明私有MyHandler并生成一个标记为注入的设置器
  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;
    }

    ...
}

如何调用上面myHandler从 a调用的同一个 Guice 处理程序WebSocketServlet

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

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

4

2 回答 2

1

查看 GitHub 示例后更新:

你如何使用 Guice 就很好。由于 MessageInbound 只有一种特殊用法,因此不需要像 AbstractGuiceWebSocketServlet 这样的糖。提供者 chatLogHdlr 再做手动构建就可以了。但是你失去了 AOP 支持。如果需要,您可能需要进行辅助注射。但现在这很好。

附带说明一下,使用构造注入而不是 setter 注入。

我立即看到了问题所在。这不是 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 (Session-per-transaction) 附近使用 txn 是要走的路。

题外话:

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

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

原答案:

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

WebSockets != Servlet。如果他们需要稍微不同的风格,这没有什么错。我什至更愿意被提醒我不是在处理 vanilla servlet。

一些观察:

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

 @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(),因为它会阻碍测试。

继续改进风格,直到您满意为止。说如果您需要更多帮助(将修改答案)。

于 2013-02-19T03:14:14.867 回答
0

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

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

于 2013-02-18T16:40:32.917 回答