Tomcat WebSocketServlet и Google Guice

у меня есть webapp, который требует использования веб-сокетов Tomcat 7.

в этом webapp все стандартные сервлеты (расширяющиеся javax.servlet.http.HttpServlet) работать красиво (и правильно) с Google Guice. Чтобы мой сервлет работал с обработчиками Guice, я просто:

  1. украсьте сервлет с @Singleton
  2. объявления частных Provider на MyHandler экземпляр и генерировать сеттер, который помечен для инъекции
  3. украсить Конструктор сервлета с @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;
    }

    ...
}

как можно вызвать тот же обработчик Guice, выше называемый myHandler С WebSocketServlet?

я не могу принять тот же стиль, что и в стандартном случае использования сервлета, потому что вместо Одноэлементного сервлета, как в случае стандартных сервлетов, каждая связь WebSocket приводит к расширению экземпляра MessageInbound; тогда соответствующий метод, который будет вызывать MyHandler вызывается из метода (например,onOpen или onClose) в экземпляре MessageInbound;не из метода внутри HttpServlet экземпляра,MyServlet выше.

что я пытался? я попробовал некоторые (концептуально неправильные) решения, такие как вызов обработчиков websocket-servlet из MessageInbound экземпляр; это, конечно, приводит к проблемам с областью видимости ниже Стек Guice следа. Что такое концептуально правильно как это сделать?

2 ответов


обновление после просмотра примера GitHub:

как вы используете Guice просто отлично. Поскольку существует только одно конкретное использование MessageInbound любого сахара, как с AbstractGuiceWebSocketServlet, не нужно. ChatLogHdlr поставщика и затем делают ручной конструкции ОК. Но вы теряете поддержку AOP. Если это необходимо, то вы могли хотеть сделать помогать впрыснуть. Но пока все в порядке.

на боковом примечании используйте инъекцию конструкции вместо сеттера инъекция.

я сразу понял, в чем проблема. это не Guice, а то, как вы используете Guice-Persist. Я не использовал GP много и все еще использую почтенный Warp-persist. Но я вижу 2 проблемы с тем, как вы используете 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 будет идти через фильтр, но все последующие сообщения не будут идти через фильтр. Использование txn только вокруг @Transactional (Session-per-transaction) - это путь.

по теме:

сколько пользователей вы собираетесь поддерживать? Если это будет хардкорный чат-сервер, я бы использовал Netty вместо этого, но он несколько более вовлечен. Погуглив нашел это:

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

оригинальный ответ:

так это вопрос о стиле?

WebSockets != Сервлеты. нет ничего плохого, если они требуют немного другого стиля. Я бы даже предпочел, чтобы мне напомнили, что я не имею дело с ванильными сервлетами.

некоторые замечания:

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

}

отсюда можно перейти к более высоким абстракциям и/или определения объема по мере необходимости. Мне не особенно нравится #getWsOutbound() как это затрудняет тестирование.

просто продолжайте улучшать стиль, пока вы не удовлетворены. Скажите, Если вам нужна дополнительная помощь (изменит ответ).


Я не совсем понял, чего вы пытаетесь достичь. Я бы искал поддержку AOP в Guice. Кажется, вам нужно, чтобы MyHandler был установлен (inject) перед использованием в некоторых методах экземпляра подкласса MessageInbound. Аспект может это сделать.

однако есть один вопрос, который вам нужно задать: где находится элемент управления (инстанциализация)? Если есть какой-то способ добавить какое-то делегирование в конфигурацию приложения Tomcat, Guice может "улучшить" Messageinbound экземпляры, которые, в свою очередь, будут иметь правильный набор MyHandler перед использованием.