Java TomcatWebSocketServlet和GoogleGuice

Java TomcatWebSocketServlet和GoogleGuice,java,servlets,websocket,tomcat7,guice,Java,Servlets,Websocket,Tomcat7,Guice,我有一个需要使用Tomcat 7 web套接字的web应用程序 在这个webapp中,所有标准servlet(那些扩展了javax.servlet.http.HttpServlet)都能很好地(正确地)与googleguice一起工作。要使Servlet与Guice处理程序一起工作,我只需: 用@Singleton 为MyHandler实例声明私有Provider,并生成标记为注入的setter 用@Inject 举例说明上述各点: @Singleton public class MyServl

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

在这个webapp中,所有标准servlet(那些扩展了
javax.servlet.http.HttpServlet
)都能很好地(正确地)与googleguice一起工作。要使Servlet与Guice处理程序一起工作,我只需:

  • @Singleton
  • MyHandler
    实例声明私有
    Provider
    ,并生成标记为注入的setter
  • @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;
        }
    
        ...
    }
    
    @Singleton
    公共类MyServlet扩展了HttpServlet{
    私人提供者myHandler;
    @注入
    MyServlet(){
    }
    @凌驾
    受保护的无效服务(..)引发ServletException{…}
    @注入
    public void setMyHandler(提供程序myHandler){
    this.myHandler=myHandler;
    }
    ...
    }
    
    如何从一个调用同一个Guice处理程序,上面称之为
    myHandler

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


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

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


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

    查看GitHub示例后更新:

    如何使用Guice很好。因为MessageInbound只有一个特定用法,所以任何类似AbstractGuiceWebSocketServlet的糖都是不必要的。提供程序chatLogHdlr,然后执行手动构造就可以了。但是你失去了AOP支持。如果需要的话,你可以做辅助注射。但现在这还可以

    另一方面,使用构造注入代替setter注入

    我立刻看出了问题所在这不是Guice,而是如何使用Guice Persist。我没有经常使用GP,仍然使用古老的Warp Persist。但我发现在代码中如何使用Guice存在两个问题:

  • 您需要注入PersistService来启动Guice Persist。这在示例中有解释

  • PersistFilter是无用的,因为只有第一次WebSocket通过筛选器,但所有后续通信都不会通过筛选器。在@Transactional(每个事务的会话数)附近使用txn是一种方法

  • 离题:

    您打算支持多少用户?如果这是一个核心的聊天服务器,我会用Netty来代替,但它有点复杂。谷歌发现:

    原始答复:

    这是一个关于风格的问题

    WebSocket!=Servlets.如果它们需要稍微不同的样式,则没有问题。我甚至更愿意被提醒,我不是在和香草小服务员打交道

    一些意见:

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

     @Singleton
     public class FooGuiceWebSocketServlet extends WebSocketServlet {...}
    
    然后将其称为

     serve("/foo").with(FooGuiceWebSocketServlet.class);
    
    现在,正如您所解释的,这是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));
        }
    
       }
    }
    
    @Singleton
    公共类ExampleWebSocketServlet扩展了AbstractGuiceWebSocketServlet{
    @凌驾
    
    公共类如果我理解您的意思,您可以重写WebSocketServlet#createWebSocketInbound,在其中创建MessageInbound的新实例?如果这是真的,那么simple只需让Guice为您创建MessageInbound(如果需要,请辅助注入)。我看到的唯一问题是http请求/响应的范围问题,因为guice筛选器使用线程局部变量来跟踪。但这是可以补偿的。我是否正确地理解了您的意见?谢谢您的评论,但我不理解这部分:“然后简单地让guice为您创建MessageInbound(如果需要,请协助注入)”谢谢你的回答。问题是这是最简单的情况;我需要跟踪连接和invidual连接ID;看看一个简单的概念证明来复制这个问题,以及我的
    createWebSocketInbound
    方法,在这个方法中,我为每个打开的websocket连接设置了
    clientNo
    。在这个结构中,我在哪里做这些您的建议是什么?我将您推荐的结构应用于我的,得到了与以前完全相同的
    java.lang.IllegalStateException
    。很棒的东西;我将根据您建议的修复将我的更改推送到github;它很有效!非常感谢!旁注:
    @Transactional
    仅在最低级别使用,即在与交互时使用de>EntityManager
    。PersistFilter在请求开始时启动事务,并在返回响应之前提交。使用[@Transactional]时,事务在方法e之前启动
    @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();
    
    }