GraphQL(三):GraphQL集成SpringBoot原理

GraphQL(二):GraphQL服務搭建中我們在pom文件中增加了如下依賴:

<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-java-tools</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphiql-spring-boot-starter</artifactId>
    <version>3.6.0</version>
</dependency>
<dependency>
    <groupId>com.graphql-java</groupId>
    <artifactId>graphql-spring-boot-starter</artifactId>
    <version>3.6.0</version>
</dependency>

接下來我們來分析其中的部分原理拉馋。

添加了上述依賴后跑揉,會引入這么幾個jar包:

  1. graphiql-spring-boot-autoconfigure: 開發(fā)者工具graphiql的自動配置jar包
  2. graphiql-spring-boot-starter: 開發(fā)者工具graphiql的實現(xiàn)
  3. graphql-java: graphql的java實現(xiàn)
  4. graphql-java-servlet: 封裝graphql服務為servlet,處理graphql的request和response
  5. graphql-java-tools: 自動加載*.graphqls文件行疏,并屏蔽graphql-java的底層實現(xiàn)細節(jié)
  6. graphql-spring-boot-autoconfigure: graphql-spring-boot的自動配置jar包
  7. graphql-spring-boot-starter: starter

開發(fā)者工具的兩個包暫不討論匆光。一切都是從graphql-spring-boot-autoconfigure開始的,通過graphql-spring-boot-autoconfigure完成了GraphQLServlet的自動配置酿联。

@Configuration
@ConfigurationProperties(prefix = "graphql.servlet")
public class GraphQLServletProperties {

    private String mapping;

    public String getMapping() {
        return mapping != null ? mapping : "/graphql";
    }

    //省略
}

在GraphQLServletProperties配置類上啟動了ConfigurationProperties终息,前綴是"graphql.servlet",因此我們可以在application.properties中以"graphql.servlet"開頭進行配置贞让,比如將endpoint從默認的“/graphql”改為“/school”:

graphql.servlet.mapping=/school

同樣的周崭,在GraphQLWebAutoConfiguration配置類中可以找到關于是否啟用GraphQLServlet和跨域訪問的配置。

GraphQLServlet

通過graphql-spring-boot-autoconfigure喳张,SpringBoot會自動掃描到GraphQLServlet的相關配置信息续镇,在GraphQLServlet的構造函數(shù)中初始化了getHandler和postHandler分別用于處理get和post請求


image

和Spring的DispatcherServlet不一樣,GraphQLServlet重寫了doGet和doPost方法销部,同時GraphQLServlet并不包含攔截器(DispatcherServlet請求執(zhí)行過程)摸航,GraphQL提供了一個GraphQLServletListener接口,允許我們針對請求執(zhí)行結果做處理:

private void doRequest(HttpServletRequest request, HttpServletResponse response, RequestHandler handler) {

    List<GraphQLServletListener.RequestCallback> requestCallbacks = runListeners(l -> l.onRequest(request, response));

    try {
        handler.handle(request, response);
        runCallbacks(requestCallbacks, c -> c.onSuccess(request, response));
    } catch (Throwable t) {
        response.setStatus(500);
        log.error("Error executing GraphQL request!", t);
        runCallbacks(requestCallbacks, c -> c.onError(request, response, t));
    } finally {
        runCallbacks(requestCallbacks, c -> c.onFinally(request, response));
    }
}

那么舅桩,如果要在GraphQL中實現(xiàn)攔截器的功能要怎么做呢酱虎?

GraphQL提供了一個Instrumentation接口:


image

允許我們在執(zhí)行前、解析前擂涛、驗證前读串、數(shù)據獲取前、字段數(shù)據獲取前(最后兩個是一樣的作用)插入自己的邏輯撒妈,但是它跟Spring的攔截器不一樣恢暖,它沒有提供跳過執(zhí)行的功能,要攔截掉執(zhí)行只能拋出異常狰右。

FiledResolverScanner

GraphQL(二):GraphQL服務搭建中我們提到杰捂,實現(xiàn)Resolver需要滿足如下約定:

1. <field>
2. is<field> – only if the field is of type Boolean
3. get<field>
4. getField<field>(最新版增加的契約)

關于這部分契約的定義在官方文檔中并沒有找到,那就從源代碼去找是如何定義契約棋蚌。

在graphql-java-tools(4.0.0版本)中琼娘,可以找到一個FieldResolverScanner類,負責了FieldResolver的掃描附鸽,找到方法findResolverMethod:

private fun findResolverMethod(field: FieldDefinition, search: Search): java.lang.reflect.Method? {

    val methods = getAllMethods(search.type)
    val argumentCount = field.inputValueDefinitions.size + if(search.requiredFirstParameterType != null) 1 else 0
    val name = field.name

    val isBoolean = isBoolean(field.type)

    // Check for the following one by one:
    //   1. Method with exact field name
    //   2. Method that returns a boolean with "is" style getter
    //   3. Method with "get" style getter
    return methods.find {
        it.name == name && verifyMethodArguments(it, argumentCount, search)
    } ?: methods.find {
        (isBoolean && it.name == "is${name.capitalize()}") && verifyMethodArguments(it, argumentCount, search)
    } ?: methods.find {
        it.name == "get${name.capitalize()}" && verifyMethodArguments(it, argumentCount, search)
    }
}

這就是定義以上契約的地方。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末瞒瘸,一起剝皮案震驚了整個濱河市坷备,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌情臭,老刑警劉巖省撑,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赌蔑,死亡現(xiàn)場離奇詭異,居然都是意外死亡竟秫,警方通過查閱死者的電腦和手機娃惯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肥败,“玉大人趾浅,你說我怎么就攤上這事÷裕” “怎么了皿哨?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纽谒。 經常有香客問我证膨,道長,這世上最難降的妖魔是什么鼓黔? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任央勒,我火速辦了婚禮,結果婚禮上澳化,老公的妹妹穿的比我還像新娘崔步。我一直安慰自己,他們只是感情好肆捕,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布刷晋。 她就那樣靜靜地躺著,像睡著了一般慎陵。 火紅的嫁衣襯著肌膚如雪眼虱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天席纽,我揣著相機與錄音捏悬,去河邊找鬼。 笑死润梯,一個胖子當著我的面吹牛过牙,可吹牛的內容都是我干的。 我是一名探鬼主播纺铭,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寇钉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了舶赔?” 一聲冷哼從身側響起扫倡,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竟纳,沒想到半個月后撵溃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疚鲤,經...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年缘挑,在試婚紗的時候發(fā)現(xiàn)自己被綠了集歇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡语淘,死狀恐怖诲宇,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情亏娜,我是刑警寧澤焕窝,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站维贺,受9級特大地震影響它掂,放射性物質發(fā)生泄漏。R本人自食惡果不足惜溯泣,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一虐秋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垃沦,春花似錦客给、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至池充,卻和暖如春桩引,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背收夸。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工坑匠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卧惜。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓厘灼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親咽瓷。 傳聞我的和親對象是個殘疾皇子设凹,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內容