Я пытаюсь перейти с Jetty 9.4 на Jetty 11 (может быть, слишком рано?) и не могу адаптировать код для настройки веб-сокетов. Способ, которым я достиг этого в 9.4, был следующим:
Server server = new Server();
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSendServerVersion(false);
HttpConnectionFactory httpFactory = new HttpConnectionFactory(httpConfig);
ServerConnector httpConnector = new ServerConnector(server, httpFactory);
httpConnector.setPort(port);
server.setConnectors(new Connector[] { httpConnector });
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
// Add a websocket to a specific path spec
ServletHolder holderEvents2 = new ServletHolder("websocket", EventsServlet.class);
context.addServlet(holderEvents2, "/events/*");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context, new DefaultHandler() });
server.setHandler(handlers);
public class EventsServlet extends WebSocketServlet {
@Override
public void configure(WebSocketServletFactory factory) {
// register a socket class as default
factory.register(EchoSocket.class);
}
}
public class EchoSocket implements WebSocketListener {
// ...
}
Поскольку класса WebSocketServlet больше нет, я немного повозился и нашел класс JettyWebSocketServlet. Согласно его JavaDoc, я думал, что он должен выглядеть следующим образом:
public class EventsServlet extends JettyWebSocketServlet {
@Override
protected void configure(JettyWebSocketServletFactory factory) {
// register a socket class as default
// factory.register(EchoSocket.class);
factory.addMapping("/", (req,res)->new EchoSocket());
}
}
но строка с addMapping на самом деле никогда не выполняется. Также JettyWebSocketServletFactory не имеет метода setDefaultMaxFrameSize, как это предлагается в JavaDoc JettyWebSocketServlet.
Кажется, все, что я могу найти в Интернете, это для Jetty <= 9.4, даже https://github.com/jetty-project/embedded-jetty-websocket-examples.
Любая помощь будет высоко оценен.
У меня была похожая проблема, хотя моя версия, работающая под Jetty 9.4, немного отличалась от вашей, используя WebSocketHandler
, а не WebSocketServlet
. У меня были некоторые проблемы со старым подходом, так как в Jetty 9.4 мне приходилось передавать свой класс слушателя как объект Class
, что делало внедрение зависимостей болезненным.
Теперь у меня это работает под Jetty 11.0.0. Я нашел ваш вопрос пару дней назад, когда пытался понять, как это сделать в Jetty 11, и это вдохновило меня на то, чтобы это действительно заработало, так что спасибо!
FWIW, моя версия Jetty 9.4 (для тривиального теста) выглядела так:
public static void main(String[] argv) throws Exception
{
int serverPort = Integer.getInteger("server.port", 8080);
Server server = new Server(serverPort);
ContextHandlerCollection handlers = new ContextHandlerCollection();
WebSocketHandler wsh = new WebSocketHandler.Simple (TestWebSocketListener.class);
handlers.addHandler(createContextHandler("/ws", wsh));
ResourceHandler rh = new ResourceHandler();
rh.setDirectoriesListed(false);
rh.setBaseResource(Resource.newClassPathResource("/WEB-STATIC/"));
handlers.addHandler(createContextHandler("/", rh));
server.setHandler(handlers);
server.start();
server.join();
}
// Convenience method to create and configure a ContextHandler.
private static ContextHandler createContextHandler(String contextPath, Handler wrappedHandler)
{
ContextHandler ch = new ContextHandler (contextPath);
ch.setHandler(wrappedHandler);
ch.clearAliasChecks();
ch.setAllowNullPathInfo(true);
return ch;
}
Здесь TestWebSocketListener
— это тривиальная реализация WebSocketListener
, которая просто реализует каждый метод слушателя и выводит аргументы в System.err
. (Я сказал, что это был тривиальный тест.) Я также отправляю сообщение клиенту в обратном вызове onWebSocketText
, просто чтобы проверить, что это работает.
Я не использую здесь DefaultHandler
— вместо этого я явно создаю ResourceHandler
, который обслуживает несколько простых статических ресурсов из дерева ресурсов, хранящегося в пути к классам (под префиксом /WEB-STATIC/
).
Версия, которая у меня работает под Jetty 11.0.0, просто меняет метод main
выше на это:
public static void main(String[] argv) throws Exception
{
int serverPort = Integer.getInteger("server.port", 8080);
Server server = new Server(serverPort);
ContextHandlerCollection handlers = new ContextHandlerCollection();
ResourceHandler rh = new ResourceHandler();
rh.setDirectoriesListed(false);
rh.setBaseResource(Resource.newClassPathResource("/WEB-STATIC/"));
handlers.addHandler(createContextHandler("/", rh));
Servlet websocketServlet = new JettyWebSocketServlet() {
@Override protected void configure(JettyWebSocketServletFactory factory) {
factory.addMapping("/", (req, res) -> new TestWebSocketListener());
}
};
ServletContextHandler servletContextHandler = new ServletContextHandler();
servletContextHandler.addServlet(new ServletHolder(websocketServlet), "/ws");
JettyWebSocketServletContainerInitializer.configure(servletContextHandler, null);
handlers.addHandler(servletContextHandler);
server.setHandler(handlers);
server.start();
server.join();
}
Вызов JettyWebSocketServletContainerInitializer.configure
важен: без него я получал исключения, жалующиеся на то, что компоненты WebSocket не были инициализированы.
Следует отметить, что порядок двух обработчиков был изменен — ранее WebSocketHandler
добавлялся перед ResourceHandler
. Однако при использовании ServletContextHandler
это возвращало 404 для путей, которые должны были быть обработаны ResourceHandler
, поэтому я поменял порядок.
TestWebSocketListener
одинаков в двух версиях. Очевидно, мне намного проще добавить внедрение зависимостей, теперь я контролирую вызов конструктора!
Еще одна вещь, которую мне пришлось изменить, — это имена артефактов Maven, которые я загрузил. Артефакт websocket-server
, похоже, больше не существует в Jetty 11, поэтому я изменил это:
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.35.v20201120</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>9.4.35.v20201120</version>
</dependency>
к этому:
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>11.0.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-server</artifactId>
<version>11.0.0</version>
</dependency>
Для тех, кому нужен TestWebSocketListener : класс TestWebSocketListener реализует WebSocketListener { @Override public void onWebSocketText (сообщение java.lang.String) { System.out.println (сообщение); } }
строка -> JettyWebSocketServletContainerInitializer.configure(servletContextHandler, null); сделал разницу. Я получал ошибку Компоненты Websocket не инициализировали ошибку без этого.
Благодаря подробному объяснению mdf я смог исправить свой код. В итоге осталось только заменить
ServletHolder holderEvents = new ServletHolder("websocket", EventsServlet.class);
context.addServlet(holderEvents, "/events/*");
с
Servlet websocketServlet = new JettyWebSocketServlet() {
@Override
protected void configure(JettyWebSocketServletFactory factory) {
factory.addMapping("/", (req, res) -> new EchoSocket());
}
};
context.addServlet(new ServletHolder(websocketServlet), "/events/*");
JettyWebSocketServletContainerInitializer.configure(context, null);
При этом я также мог избавиться от класса EventsServlet.
Вы можете найти информацию в примерах Jetty 11 https://github.com/jetty-project/embedded-jetty-websocket-examples/blob/11.0.x/native-jetty-websocket-example/src/main/java /org/eclipse/jetty/demo/EventServer.java
Обновлен с пристани 9 со следующими пакетами
org.eclipse.jetty:jetty-server:11.0.0
org.eclipse.jetty:jetty-servlet:11.0.0
org.eclipse.jetty:jetty-annotations:11.0.0
org.eclipse.jetty.websocket:websocket-jetty-server:11.0.0
org.eclipse.jetty.websocket:websocket-jetty-client:11.0.0
Обратите внимание, что имена websocket-client
и websocket-server
изменились на websocket-jetty-client
и websocket-jetty-server
.
как указывает @mdf JettyWebSocketServletContainerInitializer.configure
, позволяет избавиться от следующего сообщения:
WebSocketComponents не был создан
Теперь мое приложение работает с причалом 11.
это мой WebsocketServlet
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
public class KernelServlet extends JettyWebSocketServlet {
@Override
public void configure(JettyWebSocketServletFactory factory) {
factory.register(KernelHandler.class);
}
}
а это код инициализации сервера
Server server = new Server(port);
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/");
contextHandler.addServlet(WebClientServlet.class, "/client");
contextHandler.addServlet(KernelServlet.class, "/kernel");
JettyWebSocketServletContainerInitializer.configure(contextHandler, null);
try {
server.setHandler(contextHandler);
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
Большое спасибо за подробный и полезный ответ, который помог мне решить мою проблему. Я добавлю окончательное решение для моего кода в качестве еще одного ответа.