透过源码分析:GraphQL在开源项目skywalking中的应用
Posted NetWhite
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了透过源码分析:GraphQL在开源项目skywalking中的应用相关的知识,希望对你有一定的参考价值。
前置说明
skywalking是国人开源的一款分布式链路追踪系统(应用性能监控工具)。本文重点关注GraphQL在项目中如何应用,其它核心特性及实现,后续有时间再进行补充。
我在前面的文章:IDEA配置skywalking开发环境提到了如何在本地配置skywalking开发环境。如果感兴趣可以对着上面这篇博客把代码clone下来,配置好,对着源码来。
或者直接看下面内容,关键代码我会贴出来。
以下针对skywalking 8.5.0版本。
Skywalking应用GraphQL源码
GraphQL依赖
依赖如下,与我前面文章及示例中使用的依赖并不完全一样:
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>8.0</version>
</dependency>
初始化GraphQL
初始化方式
GraphQL实例的初始化在下面这个类里,在prepare方法里面
oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/GraphQLQueryProvider.java
关于它的初始化并没有特别多的说明,我在前面浅尝GraphQL和再谈GraphQL之在spring boot项目中快速应用的示例中用的都是类似的这种方式(因为依赖不一样,所以实际使用的类是不同的,请注意区分)
GraphQLSchema schema = SchemaParser.newParser()
.file("query-protocol/common.graphqls")
.resolvers(new Query(), new Mutation(), new HealthQuery(getManager()))
.file("query-protocol/metadata.graphqls")
.resolvers(new MetadataQuery(getManager()))
// ...省略中间这一大堆重复代码
.file("query-protocol/event.graphqls")
.resolvers(new EventQuery(getManager()))
.build()
.makeExecutableSchema();
this.graphQL = GraphQL.newGraphQL(schema).build();
初始化时间
通过debug调用栈,可以快速看到在哪里被谁调用了prepare方法初始化GraphQL:
OAPServerStartUp#main()方法和OAPServerBootstrap#start()方法都比较简单,重点看下MoudleManager#init()方法,如下:
在第一步加载所有module时,QueryMoulde初始化了GraphQL实例。
应用GraphQL实例
在前面已经初始好了GraphQL实例,需要再看下它是如何嵌套到一个Http Server里面。代码如下,还是在GraphQLProvider类里面:
start方法的调用时机就是在上面截图的第二步start那里,这个时候会调用加载的所有module的start()方法。
而GraphQLQueryHandler是一个HttpServlet的子类,GraphQL作为构造参数传递了进去:
看下GraphQLQueryHandler的代码实现,无关代码我都删除了,只留了核心代码:
@RequiredArgsConstructor
public class GraphQLQueryHandler extends JettyJsonHandler {
@Override
protected JsonElement doGet(HttpServletRequest req) {
// 不支持GET请求
throw new UnsupportedOperationException("GraphQL only supports POST method");
}
@Override
protected JsonElement doPost(HttpServletRequest req) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(req.getInputStream()));
String line;
StringBuilder request = new StringBuilder();
while ((line = reader.readLine()) != null) {
request.append(line);
}
JsonObject requestJson = gson.fromJson(request.toString(), JsonObject.class);
// 参数解析完毕,进行实际调用
return execute(requestJson.get(QUERY)
.getAsString(), gson.fromJson(requestJson.get(VARIABLES), mapOfStringObjectType));
}
private JsonObject execute(String request, Map<String, Object> variables) {
try {
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(request)
.variables(variables)
.build();
ExecutionResult executionResult = graphQL.execute(executionInput);
LOGGER.debug("Execution result is {}", executionResult);
Object data = executionResult.getData();
List<GraphQLError> errors = executionResult.getErrors();
JsonObject jsonObject = new JsonObject();
if (data != null) {
// 调用结果
jsonObject.add(DATA, gson.fromJson(gson.toJson(data), JsonObject.class));
}
// 异常处理
if (CollectionUtils.isNotEmpty(errors)) {
JsonArray errorArray = new JsonArray();
errors.forEach(error -> {
JsonObject errorJson = new JsonObject();
errorJson.addProperty(MESSAGE, error.getMessage());
errorArray.add(errorJson);
});
jsonObject.add(ERRORS, errorArray);
}
return jsonObject;
} catch (final Throwable e) {
// 异常处理的代码,删除了
return jsonObject;
}
}
}
可以看到,Get请求不支持, Post请求来的时候,解析参数,进行调用,返回结果。
在调用截图中的service.addHandler(...)方法,便会注册这个servert,调用栈如下:
这个JettyServer是skywalking自己实现的:
暴露接口,提供服务
最后看下skywalking是在什么时间启动这个Http Server,再来看下debug栈:
正好是在我们前面截图中的第三步:notifyAfterCompleted(),这时会调用所有加载module的notifyAfterCompleted方法,而这个是属于CoreModuleProvider,如下:
至此,整个流程便已经串联起来了。
以上是关于透过源码分析:GraphQL在开源项目skywalking中的应用的主要内容,如果未能解决你的问题,请参考以下文章
面试必备透过源码角度一步一步带你分析 ArrayList 扩容机制