Apache ShenYu 學習筆記一

傲世孤塵發表於2023-04-29

1、簡介

這是一個非同步的,高效能的,跨語言的,響應式的 API 閘道器。

2、首次體驗

本次體驗基本參照官方快速開始文件步驟

2.1、本地環境

  • 開發工具:IDEA
  • JDK:1.8

2.2、下載程式碼

git clone https://github.com/apache/shenyu.git
cd shenyu
mvn clean install -Dmaven.javadoc.skip=true -B -Drat.skip=true -Djacoco.skip=true -DskipITs -DskipTests

2.3、啟動shenyu-admin

  • IDEA開啟上一步下載好的專案
  • 找到shenyu-admin子專案,執行ShenyuAdminBootstrap
  • 該專案預設使用H2資料庫,首次啟動會自行初始化。預設web埠為:9095,預設賬號密碼為:admin/123456
  • 瀏覽器訪問:http://localhost:9095 並登陸,可以看到如下介面:

2.4、啟動shenyu-bootstrap

  • 找到shenyu-bootstrap子專案,修改application.ymlshenyu.local.enabled的值為true,方便本地除錯。
  • 執行ShenyuBootstrapApplication
  • 該專案預設埠為:9195,後面設定路由規則需要用到

2.5、測試準備

  • 由於首次體驗我們需要測試http介面轉發,因此本地啟動用於測試的web專案,提供一個待測試的介面:http://localhost:8081/test/hello 如下圖:

2.6、新增路由規則

待測試的介面準備好了,接下來我們需要在ShenYu中新增路由規則,我直接透過終端傳送請求如下:

curl --location --request POST 'http://localhost:9195/shenyu/plugin/selectorAndRules' \
--header 'Content-Type: application/json' \
--header 'localKey: 123456' \
--data-raw '{
    "pluginName": "divide",
    "selectorHandler": "[{\"upstreamUrl\":\"127.0.0.1:8081\"}]",
    "conditionDataList": [{
        "paramType": "uri",
        "operator": "match",
        "paramValue": "/**"
    }],
    "ruleDataList": [{
        "ruleHandler": "{\"loadBalance\":\"random\"}",
        "conditionDataList": [{
            "paramType": "uri",
            "operator": "match",
            "paramValue": "/**"
        }]
    }]
}'

2.7、測試轉發

根據上面的對映規則,我們直接訪問: http://localhost:9195/test/hello ,結果如下:

至此,首次體驗已經完成。接下來,我想繼續瞭解下本專案。

3、轉發實現流程探究

以下的探究基於上面2.x體驗流程

3.1、單一職責外掛

透過官方文件:https://shenyu.apache.org/zh/docs/developer/custom-plugin ,可以看到如下內容:

結合2.6新增路由規則中涉及的plugin:divide,於是本次探究我們圍繞divide外掛展開

3.2、divide外掛

  • shenyu專案下,可以看到一個子模組shenyu-plugin,點開後可以看到該模組下已經提供了眾多外掛實現

  • 點開shenyu-plugin-divdie,可以看到DividePlugin類,該類繼承自org.apache.shenyu.plugin.base.AbstractShenyuPlugin,與官方文件描述如出一轍

  • org.apache.shenyu.plugin.base.AbstractShenyuPlugin.execute方法中打斷點除錯如下:

  • 此處正好印證官方文件關於外掛的描述,具體的轉發邏輯由外掛各自實現,我們可以透過自定義外掛的方式進行擴充套件

  • 那麼一個請求過來?閘道器是如何找到具體外掛的呢?

3.3、ShenyuWebHandler

  • 斷點透過方法呼叫棧發現,該請求從上游方法org.apache.shenyu.web.handler.ShenyuWebHandler.handle過來:

  • ShenyuWebHandler類實現了org.springframework.web.server.WebHandler介面。

  • 可以看到,該handler方法拿到了plugins,並透過Reactor非同步地將exchange釋出出去

  • 然後透過責任鏈機制,按照外掛定義的順序依次匹配。未匹配上則忽略,匹配上則由對應的外掛處理,正好與3.2步驟中的divide外掛銜接上。匹配邏輯如下:

  • 由於這是首次體驗,我不想過多的探究細節,因此外掛匹配、執行的細節此處暫且跳過,我們繼續往下探究plugins從何而來?

3.4、shenyu-spring-boot-starter-gateway

  • 繼續追溯,發現ShenyuWebHandler例項的生產地位於shenyu-spring-boot-starter-gateway中的ShenyuConfiguration

  • 透過該方法發現,外掛列表資訊從方法引數ObjectProvider<List<ShenyuPlugin>> plugins獲取,因此我們只要找到外掛Bean例項生成的位置即可

3.5、shenyu-spring-boot-starter-plugin-divide

  • 於是很輕易的發現,在shenyu-spring-boot-starter-plugin-divide子專案下,有一個類:DividePluginConfiguration,包含如下程式碼:

  • 因此,本次探究過程至此結束

4、本次學習總結

  • 專案主要模組
    • shenyu-admin:後臺配置、監控
    • shenyu-bootstrap:服務端配置、啟動入口
    • shenyu-plugin:服務端外掛合集
    • shenyu-web: 服務端web層上游基礎功能封裝
    • shenyu-spring-boot-starter:將其他功能模組與springboot進行整合
  • 外掛開發大致流程
    • shenyu-plugin下新建外掛子模組,編寫外掛入口類(實現ShenyuPlugin介面,或繼承AbstractShenyuPlugin類)
    • 定義好外掛名稱、優先順序(Order)、skip邏輯、外掛處理邏輯(execute)
    • shenyu-spring-boot-starter-plugin編寫自定義外掛對應的starter
  • 轉發大致流程
    • 專案啟動後,從bean容器載入外掛列表
    • 請求過來後,首先到達org.apache.shenyu.web.handler.ShenyuWebHandler.handle,透過Reactor非同步地將exchange釋出出去
    • 然後透過責任鏈機制,按照外掛定義的順序依次匹配。未匹配上則忽略,匹配上則由對應的外掛處理
    • 最後由具體的外掛(如:divide外掛,將http請求轉發到目標地址)處理

5、聯絡我吧

我是一個熱愛開源的小菜雞,如果本文吸引到了你,歡迎透過下面的方式與我取得聯絡

相關文章