嵌入式Jetty 10搭配graphql-java实现GraphQL subscription适配问题
Jetty 10 整合 graphql-java WebSocket 端点配置解决方案
方案一:保留原有JSR356端点配置(改造成本最低)
Jetty 10 全面切换到Jakarta EE 9命名空间,原javax.websocket相关实现已迁移到jakarta.websocket包下,你之前注释掉的JSR356实现依赖需要替换为对应Jakarta版本,不需要改用Jetty原生WebSocket API。
调整依赖配置
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}" // 替换原javax-websocket-server-impl为Jakarta版本实现 implementation "org.eclipse.jetty.websocket:websocket-jakarta-server:${jettyVersion}" }
修改服务启动配置
将原WebSocketServerContainerInitializer替换为Jakarta版本的初始化类,原有addEndpoint逻辑完全不需要修改:
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServerContainerInitializer; // 原有服务启动代码保持不变 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); // 仅替换初始化类,其余配置逻辑不变 JakartaWebSocketServerContainerInitializer.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();
方案二:适配Jetty 10原生WebSocket API
如果要使用Jetty原生WebSocket API,不需要依赖JSR356实现,直接将GraphQLWebsocketServlet包装为Jetty原生WebSocket Servlet注册即可:
自定义Jetty WebSocket Servlet
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet; import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory; import javax.servlet.ServletException; public class GraphQLJettyWebSocketServlet extends JettyWebSocketServlet { private final GraphQLWebsocketServlet delegate; public GraphQLJettyWebSocketServlet(GraphQLWebsocketServlet delegate) { this.delegate = delegate; } @Override protected void configure(JettyWebSocketServletFactory factory) { factory.addMapping("/subscriptions", (upgradeRequest, upgradeResponse) -> delegate); } // 按需重写init/destroy方法透传到delegate @Override public void init() throws ServletException { delegate.init(getServletConfig()); super.init(); } @Override public void destroy() { delegate.destroy(); super.destroy(); } }
修改服务启动配置
删除原有WebSocketServerContainerInitializer配置逻辑,直接注册自定义的Servlet:
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"); // 注册GraphQL WebSocket处理Servlet context.addServlet(new ServletHolder(new GraphQLJettyWebSocketServlet(yourGraphQLWebsocketServletInstance)), "/subscriptions/*"); server.setHandler(context); server.start(); server.dump(System.err); server.join();
注意事项
- 若使用方案一,需确保你的
graphql-java-servlet版本支持Jakarta EE 9命名空间,否则会出现javax.websocket类找不到的异常,可升级到最新版本的graphql-java-servlet解决该问题。 - Jetty 10 不再支持
javax.websocket命名空间的实现,请勿混用Jetty9和Jetty10的WebSocket依赖。
内容的提问来源于stack exchange,提问作者Manticore
相关产品推荐
相关产品推荐

