简体   繁体   English

使用 Jetty 11 设置 websockets

[英]Set up websockets with Jetty 11

I am trying to migrate from Jetty 9.4 to Jetty 11 (maybe too early?) and failing in adapting the code for setting up websockets.我正在尝试从 Jetty 9.4 迁移到 Jetty 11(可能为时过早?)并且未能调整用于设置 websockets 的代码。 The way I achieved this in 9.4 was as follows:我在 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 {
    // ...
}

As there is no WebSocketServlet class anymore, I fiddled around a bit and found the class JettyWebSocketServlet.由于没有 WebSocketServlet class 了,我四处摸索了一下,找到了 class JettyWebSocketServlet。 According to its JavaDoc, I thought it should like as follows:根据其 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());

    }
}

but the line with addMapping is actually never executed.但实际上从未执行过带有 addMapping 的行。 Also JettyWebSocketServletFactory does not have a method called setDefaultMaxFrameSize as suggested by the JavaDoc of JettyWebSocketServlet.此外,JettyWebSocketServletFactory 没有 JettyWebSocketServlet 的 JavaDoc 建议的名为 setDefaultMaxFrameSize 的方法。

All I seem to be able to find on the web is for Jetty <= 9.4, even https://github.com/jetty-project/embedded-jetty-websocket-examples .我似乎能够在 web 上找到的是 Jetty <= 9.4,甚至https://github.com/jetty-project/embedded-jetty-websocket-examples

Any help would be highly appreciated.任何帮助将不胜感激。

I had a similar problem, though my version running under Jetty 9.4 was a bit different to yours, using WebSocketHandler rather than WebSocketServlet .我有一个类似的问题,虽然我在 Jetty 9.4 下运行的版本与你的有点不同,使用WebSocketHandler而不是WebSocketServlet I was having some problems with the old approach, since under Jetty 9.4 I had to pass my listener class as a Class object, which makes dependency injection a pain.我在使用旧方法时遇到了一些问题,因为在 Jetty 9.4 下,我必须将我的侦听器 class 作为Class object 传递,这使得依赖注入变得很痛苦。

I have now got this working under Jetty 11.0.0 though.我现在已经在 Jetty 11.0.0 下工作了。 I found your question a couple of days ago while I was trying to work out how to do this in Jetty 11, and it inspired me to actually get this working, so thanks!几天前,当我试图弄清楚如何在 Jetty 11 中执行此操作时,我发现了您的问题,它启发了我实际实现此功能,非常感谢!

FWIW, my Jetty 9.4 version (for a trivial test) looked like this: 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;
}

Here, TestWebSocketListener is a trivial implementation of WebSocketListener which just implements each listener method and prints the arguments to System.err .在这里, TestWebSocketListenerWebSocketListener的简单实现,它只实现每个侦听器方法并将 arguments 打印到System.err (I did say this was a trivial test.) I also send a message back to the client in the onWebSocketText callback, just to check that this works. (我确实说过这是一个微不足道的测试。)我还在onWebSocketText回调中向客户端发回一条消息,只是为了检查它是否有效。

I'm not using DefaultHandler here - instead, I explicitly create a ResourceHandler which serves a few simple static resources from a resource tree stored within the classpath (under the /WEB-STATIC/ prefix).我在这里没有使用DefaultHandler - 相反,我明确地创建了一个ResourceHandler ,它从存储在类路径(在/WEB-STATIC/前缀下)的资源树中提供一些简单的 static 资源。

The version I have working under Jetty 11.0.0 just changes the main method above to this:我在 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();
}

The call to JettyWebSocketServletContainerInitializer.configure is important: without that I got exceptions complaining that the WebSocket components had not been initialised.JettyWebSocketServletContainerInitializer.configure的调用很重要:否则我会收到异常,抱怨 WebSocket 组件尚未初始化。

One thing to note is that the order of the two handlers has been changed - previously, the WebSocketHandler was added before the ResourceHandler .需要注意的一件事是两个处理程序的顺序已更改 - 以前, WebSocketHandler添加在ResourceHandler之前。 However, when using ServletContextHandler this was returning 404s for paths that should have been handled by the ResourceHandler , so I swapped the order.但是,当使用ServletContextHandler时,这会为本应由ResourceHandler处理的路径返回 404,因此我交换了顺序。

The TestWebSocketListener is identical between the two versions.两个版本之间的TestWebSocketListener是相同的。 Obviously, it's a lot easier for me to add dependency injection now I control the constructor call!显然,现在我控制了构造函数调用,添加依赖注入变得容易多了!

The other thing I had to change was the names of the Maven artifacts I pulled in. The websocket-server artifact no longer seems to exist in Jetty 11, so I changed this:我必须更改的另一件事是我引入的 Maven 工件的名称。websocket 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>

to this:对此:

<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>

Thanks to the detailed explanation by mdf, I was able to fix my code.感谢 mdf 的详细解释,我能够修复我的代码。 In the end, I only had to replace最后,我只需要更换

ServletHolder holderEvents = new ServletHolder("websocket", EventsServlet.class);
context.addServlet(holderEvents, "/events/*");

with

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

With this I could also get rid of the EventsServlet class.有了这个,我也可以摆脱 EventsServlet class。

You can find info in the Jetty 11 examples 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您可以在 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

Upgraded from jetty 9 with the following packages使用以下软件包从 jetty 9 升级

  1. org.eclipse.jetty:jetty-server:11.0.0
  2. org.eclipse.jetty:jetty-servlet:11.0.0
  3. org.eclipse.jetty:jetty-annotations:11.0.0
  4. org.eclipse.jetty.websocket:websocket-jetty-server:11.0.0
  5. org.eclipse.jetty.websocket:websocket-jetty-client:11.0.0

Notice that the names of the websocket-client and websocket-server changed to websocket-jetty-client and websocket-jetty-server请注意, websocket-clientwebsocket-server的名称更改为websocket-jetty-clientwebsocket-jetty-server

as pointed by @mdf JettyWebSocketServletContainerInitializer.configure enables to get rid of the following message:正如@mdf JettyWebSocketServletContainerInitializer.configure所指出的那样,可以摆脱以下消息:

WebSocketComponents has not been created尚未创建 WebSocketComponents

Now my app works with jetty 11.现在我的应用程序适用于 jetty 11。

this is my WebsocketServlet这是我的 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);
    }
}

and this is the server init code这是服务器初始化代码

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM