嵌入 Jetty 10 的 GraphQL 订阅

Posted

技术标签:

【中文标题】嵌入 Jetty 10 的 GraphQL 订阅【英文标题】:GraphQL subscription with Jetty 10 embedded 【发布时间】:2021-11-11 09:54:44 【问题描述】:

我的目标是让最新的 Graphql-java 的功能版本与 jetty 版本 10 混合。

我已经使用不同的方法做了很多测试,现在我被 9.4 和 10.0.6 版本之间的 WebSocket 实现(在 Jetty 上)的差异所困扰。

为了测试实现,我正在处理来自graphQL repository sample 的示例。

我的测试是在子项目 servlet-hello-world 上完成的,其中完成了一个简单的 graphQL 订阅并在 jetty 9.4 上工作

我已更新 gradle 以使用最新版本

def jettyVersion = '9.4.43.v20210629'

dependencies 
    implementation "com.graphql-java-kickstart:graphql-java-servlet:$LIB_GRAPHQL_SERVLET_VER"
    implementation "io.projectreactor:reactor-core:3.4.9"
    implementation 'ch.qos.logback:logback-classic:1.2.5'
    implementation 'org.slf4j:slf4j-simple:2.0.0-alpha4'
    implementation "org.eclipse.jetty:jetty-webapp:$jettyVersion"
    implementation "org.eclipse.jetty:jetty-annotations:$jettyVersion"
    implementation "org.eclipse.jetty.websocket:websocket-api:$jettyVersion"
    implementation "org.eclipse.jetty.websocket:websocket-server:$jettyVersion"
    implementation "org.eclipse.jetty.websocket:javax-websocket-server-impl:$jettyVersion"
    implementation "org.eclipse.jetty.websocket:websocket-common:$jettyVersion"


def jettyVersion = '10.0.6'

dependencies 
    implementation "com.graphql-java-kickstart:graphql-java-servlet:$LIB_GRAPHQL_SERVLET_VER"
    implementation "io.projectreactor:reactor-core:3.4.9"
    implementation 'ch.qos.logback:logback-classic:1.2.5'
    implementation 'org.slf4j:slf4j-simple:2.0.0-alpha4'
//    implementation "org.eclipse.jetty:jetty-webapp:$jettyVersion"
//    implementation "org.eclipse.jetty:jetty-annotations:$jettyVersion"
    implementation "org.eclipse.jetty.websocket:websocket-jetty-api:$jettyVersion"
    implementation "org.eclipse.jetty.websocket:websocket-jetty-server:$jettyVersion"
//    implementation "org.eclipse.jetty.websocket:javax-websocket-server-impl:$jettyVersion"
//    implementation "org.eclipse.jetty.websocket:websocket-common:$jettyVersion"

然后我被困在 API 的变化上,其中 WebSocketServletContainerInitalizer 被 JettyWebSocketServletContainerInitializer 替换:

    var server = new Server();
    var connector = new ServerConnector(server);
    connector.setPort(PORT);
    server.addConnector(connector);

    var context = new ServletContextHandler(ServletContextHandler.SESSIONS);
    context.setContextPath("/");
    context.addServlet(HelloServlet.class, "/graphql");
    server.setHandler(context);

    WebSocketServerContainerInitializer.configure(
        context,
        (servletContext, serverContainer) ->
            serverContainer.addEndpoint(
                ServerEndpointConfig.Builder.create(SubscriptionEndpoint.class, "/subscriptions")
                    .configurator(new GraphQLWSEndpointConfigurer())
                    .build()));

    server.setHandler(context);

    server.start();
    server.dump(System.err);
    server.join();
  

不同之处在于配置器已将配置器的类型从 ServletContainer 更改为 JettyWebSocketServerContainer,并且不再有 addEndpoint 方法可以连接我的 SubscriptionEndpoint。

我完全不知道如何连接我的GraphQLWebsocketServlet

【问题讨论】:

【参考方案1】:

旧版本的 Jetty 是 websocket 实现中立的(核心、javax.websocket、jetty 原生 websocket 等)。当同时使用多个实现时,这被证明太复杂了。

新的 Jetty 10+ 实施要求您为正在使用的实施使用适当的 <Impl>WebSocketServletContainerInitializer。 (其中<Impl>JavaxJakartaJetty 之一)

由于您使用的是javax.websocket,因此这里是要使用的适当类。

JavaxWebSocketServletContainerInitializer.configure(context, (servletContext, wsContainer) ->

    // This lambda will be called at the appropriate place in the
    // ServletContext initialization phase where you can initialize
    // and configure  your websocket container.

    // Configure defaults for container
    wsContainer.setDefaultMaxTextMessageBufferSize(65535);

    // Add WebSocket endpoint to javax.websocket layer
    wsContainer.addEndpoint(
        ServerEndpointConfig.Builder.create(
            SubscriptionEndpoint.class, "/subscriptions")
            .configurator(new GraphQLWSEndpointConfigurer())
        .build());
);

【讨论】:

谢谢你,解决方案就是这么简单,但是我没有找到任何迁移指南,Jetty 文档在 Websocket 实现章节上只是说“TODO”;) 我刚用github.com/jetty-project/embedded-jetty-websocket-examples/tree/…

以上是关于嵌入 Jetty 10 的 GraphQL 订阅的主要内容,如果未能解决你的问题,请参考以下文章

使用 GraphQL 设置订阅问题

无法启动嵌入式 Jetty 服务器

Apollo GraphQL:MQTT 订阅代理以仅提供已发布的数据

Jetty 9.0 嵌入了带有 SPDY 但没有 SSL/NPN 的配置

在 Spring 中在嵌入式 Jetty 上配置 Spring Security

GraphQL:突变运行时订阅未触发