Spring Boot应用能否暴露多GraphQL端点并使用独立Schema?
Spring 多独立Schema GraphQL端点实现方案
完全可行,Spring GraphQL支持在同一应用中创建多个独立的GraphQL端点,每个端点绑定专属的Schema、数据解析器(DataFetcher),不会合并不同Schema,从根本上避免命名冲突问题。以下是具体实现方案:
实现步骤(WebFlux环境)
1. 引入依赖
在pom.xml中添加Spring GraphQL和WebFlux starter:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-graphql</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency>
2. 准备独立Schema文件
在src/main/resources下创建两个独立目录存放Schema,避免文件混淆:
src/main/resources/old/schema.graphqls(旧API Schema):
type Query { user(id: ID!): User } type User { id: ID! name: String! }
src/main/resources/new/schema.graphqls(新API Schema):
type Query { user(id: ID!): User } type User { id: ID! email: String! }
两个Schema中User类型字段不同,存在命名冲突,但各自独立维护。
3. 配置旧API的GraphQL组件
创建OldGraphQLConfig.java,定义旧API专属的Schema加载和数据解析逻辑:
package com.example.demo.config; import graphql.schema.DataFetcher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.graphql.execution.DefaultGraphQlSource; import org.springframework.graphql.execution.GraphQlSource; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.WebGraphQlRequestHandler; import org.springframework.graphql.schema.GraphQlSchemaBuilder; import org.springframework.graphql.schema.SchemaResourceBuilder; import java.util.Map; @Configuration public class OldGraphQLConfig { @Bean public GraphQlSource oldGraphQlSource() { // 加载旧API的Schema文件 SchemaResourceBuilder schemaResourceBuilder = new SchemaResourceBuilder() .schemaLocations("classpath:old/schema.graphqls"); GraphQlSchemaBuilder schemaBuilder = GraphQlSchemaBuilder.newSchema() .schemaResources(schemaResourceBuilder.build()); // 注册旧API的User数据解析器 DataFetcher<?> userFetcher = env -> { String id = env.getArgument("id"); return Map.of("id", id, "name", "Old User " + id); }; schemaBuilder.addDataFetcher("Query.user", userFetcher); return new DefaultGraphQlSource(schemaBuilder.build()); } @Bean public WebGraphQlHandler oldWebGraphQlHandler(GraphQlSource oldGraphQlSource) { return WebGraphQlRequestHandler.builder(oldGraphQlSource).build(); } }
4. 配置新API的GraphQL组件
创建NewGraphQLConfig.java,定义新API专属的组件:
package com.example.demo.config; import graphql.schema.DataFetcher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.graphql.execution.DefaultGraphQlSource; import org.springframework.graphql.execution.GraphQlSource; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.graphql.server.WebGraphQlRequestHandler; import org.springframework.graphql.schema.GraphQlSchemaBuilder; import org.springframework.graphql.schema.SchemaResourceBuilder; import java.util.Map; @Configuration public class NewGraphQLConfig { @Bean public GraphQlSource newGraphQlSource() { SchemaResourceBuilder schemaResourceBuilder = new SchemaResourceBuilder() .schemaLocations("classpath:new/schema.graphqls"); GraphQlSchemaBuilder schemaBuilder = GraphQlSchemaBuilder.newSchema() .schemaResources(schemaResourceBuilder.build()); // 注册新API的User数据解析器 DataFetcher<?> userFetcher = env -> { String id = env.getArgument("id"); return Map.of("id", id, "email", "new.user." + id + "@example.com"); }; schemaBuilder.addDataFetcher("Query.user", userFetcher); return new DefaultGraphQlSource(schemaBuilder.build()); } @Bean public WebGraphQlHandler newWebGraphQlHandler(GraphQlSource newGraphQlSource) { return WebGraphQlRequestHandler.builder(newGraphQlSource).build(); } }
5. 配置端点路由
创建GraphQLRouterConfig.java,将不同URL映射到对应的处理器:
package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.graphql.server.WebGraphQlHandler; import org.springframework.web.reactive.function.server.RequestPredicates; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; @Configuration public class GraphQLRouterConfig { @Bean public RouterFunction<ServerResponse> graphqlRoutes(WebGraphQlHandler oldWebGraphQlHandler, WebGraphQlHandler newWebGraphQlHandler) { return RouterFunctions.route() .POST("/old-api/graphql", RequestPredicates.contentType(org.springframework.http.MediaType.APPLICATION_JSON), oldWebGraphQlHandler::handleRequest) .POST("/new-api/graphql", RequestPredicates.contentType(org.springframework.http.MediaType.APPLICATION_JSON), newWebGraphQlHandler::handleRequest) .build(); } }
Servlet环境替代方案
如果使用传统Servlet环境(依赖spring-boot-starter-web),可以通过注册多个GraphQlServlet实现:
1. 替换依赖
将WebFlux依赖替换为Web starter:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2. 配置Servlet注册
创建OldGraphQLServletConfig.java:
package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.graphql.execution.GraphQlSource; import org.springframework.graphql.server.web.servlet.GraphQlServlet; import org.springframework.boot.web.servlet.ServletRegistrationBean; @Configuration public class OldGraphQLServletConfig { @Bean public GraphQlServlet oldGraphQlServlet(GraphQlSource oldGraphQlSource) { return new GraphQlServlet(oldGraphQlSource); } @Bean public ServletRegistrationBean<GraphQlServlet> oldGraphQlServletRegistration(GraphQlServlet oldGraphQlServlet) { ServletRegistrationBean<GraphQlServlet> registration = new ServletRegistrationBean<>(oldGraphQlServlet, "/old-api/graphql"); registration.setName("OldGraphQLServlet"); return registration; } }
同理创建NewGraphQLServletConfig.java,修改路径为/new-api/graphql,Servlet名称改为NewGraphQLServlet即可。
验证效果
启动应用后,分别访问两个端点测试:
- 访问
/old-api/graphql,执行查询:
query { user(id: "1") { id name } }
返回结果:
{"data":{"user":{"id":"1","name":"Old User 1"}}}
- 访问
/new-api/graphql,执行查询:
query { user(id: "1") { id email } }
返回结果:
{"data":{"user":{"id":"1","email":"new.user.1@example.com"}}}
两个端点完全独立,Schema互不干扰,命名冲突问题解决。
内容的提问来源于stack exchange,提问作者user7963071
相关产品推荐
相关产品推荐

