Подтвердить что ты не робот

Tomcat WebSocketServlet и Google Guice

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

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

  • украсить сервлет @Singleton
  • объявить частный Provider для MyHandler экземпляр и создать сеттер, который помечен для инъекций
  • украсить конструктор сервлета @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?

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

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

4b9b3361

Ответ 1

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

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

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

Я сразу понял, в чем проблема. Это не Guice, а скорее как вы используете Guice-Persist. Я много не использовал GP и все еще использую почтенный Warp-persist. Но я вижу 2 проблемы с тем, как вы используете Guice-persist в своем коде:

  • Вам нужно ввести 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();
    }
    }
    
  • PersistFilter бесполезен, поскольку только первый раз WebSocket будет проходить через фильтр, но все последующие сообщения не будут проходить через фильтр. Использование txn только вокруг @Transactional (сеанс за транзакцию) - это путь.

Не по теме:

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

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

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

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

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

Некоторые наблюдения:

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

}

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

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

Ответ 2

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

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