GraphQL杂谈(一):starter及工程化模块化及理解

项目地址

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 提供servlet入口 -->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>LATEST</version>
</dependency>
<!-- graphiql 提供查询界面-->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphiql-spring-boot-starter</artifactId>
<version>LATEST</version>
</dependency>
<!-- 解析schema文件,resolver等 -->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>LATEST</version>
</dependency>

配置过程简单分析

GraphQLWebAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Autowired(required = false)
private List<GraphQLServletListener> listeners;

@Autowired(required = false)
private Instrumentation instrumentation;

@Autowired(required = false)
private GraphQLErrorHandler errorHandler;

@Autowired(required = false)
private Map<String, ExecutionStrategy> executionStrategies;

@Autowired(required = false)
private GraphQLContextBuilder contextBuilder;

@Autowired(required = false)
private GraphQLRootObjectBuilder graphQLRootObjectBuilder;

@Autowired(required = false)
private ObjectMapperConfigurer objectMapperConfigurer;

...

// GraphQLServlet 创建
@Bean
@ConditionalOnMissingBean
public GraphQLServlet graphQLServlet(GraphQLSchemaProvider schemaProvider, ExecutionStrategyProvider executionStrategyProvider) {
return new SimpleGraphQLServlet(schemaProvider, executionStrategyProvider, objectMapperConfigurer, listeners, instrumentation, errorHandler, contextBuilder, graphQLRootObjectBuilder);
}

...

GraphiQLAutoConfiguration

1
2
3
4
5
6
// graphiql 查询页面
@Bean
@ConditionalOnProperty(value = "graphiql.enabled", havingValue = "true", matchIfMissing = true)
GraphiQLController graphiQLController() {
return new GraphiQLController();
}

GraphQLJavaToolsAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@Autowired(required = false)
private SchemaParserDictionary dictionary;

@Autowired(required = false)
private GraphQLScalarType[] scalars;

@Autowired(required = false)
private SchemaParserOptions options;

@Autowired
private ApplicationContext applicationContext;

@Bean
@ConditionalOnBean({GraphQLResolver.class})
@ConditionalOnMissingBean
public SchemaParser schemaParser(List<GraphQLResolver<?>> resolvers) throws IOException {

SchemaParserBuilder builder = dictionary != null ? new SchemaParserBuilder(dictionary) : new SchemaParserBuilder();

// 读取classpath下所有schema
Resource[] resources = applicationContext.getResources("classpath*:**/*.graphqls");
if(resources.length <= 0) {
throw new IllegalStateException("No *.graphqls files found on classpath. Please add a graphql schema to the classpath or add a SchemaParser bean to your application context.");
}

for(Resource resource : resources) {
StringWriter writer = new StringWriter();
IOUtils.copy(resource.getInputStream(), writer);
builder.schemaString(writer.toString());
}

if(scalars != null) {
builder.scalars(scalars);
}

if(options != null) {
builder.options(options);
}

return builder.resolvers(resolvers)
.build();
}


// 解析schema
@Bean
@ConditionalOnBean(SchemaParser.class)
@ConditionalOnMissingBean({GraphQLSchema.class, GraphQLSchemaProvider.class})
public GraphQLSchema graphQLSchema(SchemaParser schemaParser) {
return schemaParser.makeExecutableSchema();
}

关于工程化

按照MVC的设计方法,resolver相当于controller层

关于模块化

schema 模块化

classpath 下所有 schema 文件都会加载,利用 extend type 的 feature 可以实现简单的模块化划分

1
2
3
4
resources/graphqls
├── common.graphqls
├── mongo.graphqls
└── ssl.graphqls

common.graphqls

1
2
3
type Query {
version: String!
}

mongo.graphqls

1
2
3
4
extend type Query {
collectionNames: [String]
collectionData(collectionName: String!): [String]
}

Resolver 模块化

FieldResolverScanner会在GraphQLQueryResolver所有实现类方法中查找schema的query

1
2
3
4
query
├── CommonQueryResolver.java
├── MongoQueryResolver.java
└── SSLQueryResolver.java