前置說明
Skywalking應用GraphQL源碼
GraphQL依賴
初始化GraphQL
初始化方式
初始化時間
應用GraphQL執行個體
暴露接口,提供服務
前置說明
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:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9UEVOhXVU90MNpmTzc2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL2kjN2EDO1kDMxEjNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
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,如下:
至此,整個流程便已經串聯起來了。