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
?
я не могу принять тот же стиль, что и в стандартном случае использования сервлета, потому что вместо Одноэлементного сервлета, как в случае стандартных сервлетов, каждая связь 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 в своем коде:
-
вам нужно ввести 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 (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 перед использованием.