2012-12-19 40 views
27

我有一个web应用程序,它需要使用Tomcat 7网络套接字。Tomcat WebSocketServlet和Google Guice

在这个web应用程序中,所有标准的Servlets(扩展为javax.servlet.http.HttpServlet)与很好地(并正确地)工作。Google Guice。为了使我的Servlet的工作与吉斯处理我简单:

  1. 装饰与@Singleton
  2. servlet的声明私有ProviderMyHandler例如&生成被标记为注射
  3. @Inject
  4. 装饰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; 
    } 

    ... 
} 

如何调用相同的Guice处理程序,以上称为myHandlerWebSocketServlet

我不能采用与标准servlet用例相同的样式,因为与每个WebSocket通信都有一个实例延伸MessageInbound;而不是像标准servlet中的单例servlet一样,那么将调用MyHandler的适当方法从MessageInbound实例内的方法(例如onOpenonClose)调用; 而不是来自HttpServlet实例中的方法,如上面的MyServlet

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

+0

如果我理解你,你重写WebSocketServlet#createWebSocketInbound在哪里创建一个MessageInbound的新实例?如果这是真的,那么简单的让Guice为你创建MessageInbound(如果需要,可以辅助注入)。我看到的唯一问题是与http请求/响应的范围,因为guice过滤器使用线程本地来跟踪。但是这可以得到补偿。我跟着你了吗? –

+0

感谢您的评论,但我不明白这一部分:“那么简单就让Guice为您创建MessageInbound(如果需要,则协助注入)” –

回答

1

看看GitHub示例后的更新示例:

如何使用Guice就好了。由于MessageInbound只有一个特定的用法,所以不需要像AbstractGuiceWebSocketServlet那样的糖。供应商chatLogHdlr,然后做手动施工是好的。但是你失去了AOP支持。如果需要,您可能需要进行辅助注射。但现在这没问题。

在附注中,使用施工注入而不是设置注入。

我马上看到了什么问题。 这不是Guice,而是你如何使用Guice-Persist。我没有使用GP很多,仍然使用历史悠久的Warp-persist。但是,我看到2个问题您如何使用吉斯 - 坚持代码:

  1. 你需要注入PersistService开始吉斯 - 坚持。这在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是一条路。

题外话:

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

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

原来的答复:

因此,这是一个关于风格的问题?

WebSockets!= Servlets。如果他们需要稍微不同的风格,没有什么不对。我甚至更喜欢提醒我没有处理香草servlets。

一些观察:

WebSocketServlet没有什么特别的。你可以很容易地将它与Guice-Servlet一起使用。例如: -

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

然后refernce它作为

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

} 

您可以根据需要何去何从更高的抽象和/或scopings。我不特别喜欢#getWsOutbound(),因为它阻碍了测试。

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

+0

感谢您的回答。问题是这是最简单的情况;我需要跟踪连接和各个连接ID;看看一个简单的概念证明来复制[在github上]问题(https://github.com/jvzammit/wspoc),以及我在[MainSocket.java]中的'createWebSocketInbound'方法(https:// github.com/jvzammit/wspoc/blob/master/wspoc/poc-web/src/main/java/com/cif/dt/app/websocket/MainSocket.java),我为每个打开的websocket连接设置一个'clientNo' 。你在这个结构中建议我在哪里做? –

+0

我将你的推荐结构应用到了我的[概念验证](https://github.com/jvzammit/wspoc),并得到了与之前一样的'java.lang.IllegalStateException'。 –

+0

已更新的答案,希望能够解决您的问题。 –

0

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

但是,有一个问题需要问:(实例化)控制在哪里?如果可以在Tomcat应用程序配置中添加某种委派,Guice可以“增强”MessageInbound实例,然后在使用前设置适当的MyHandler。