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.yml
中shenyu.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、聯絡我吧
我是一個熱愛開源的小菜雞,如果本文吸引到了你,歡迎透過下面的方式與我取得聯絡
- 本文作者:傲世孤塵,dromara社群開源專案(neutrino-proxy)作者
- 微訊號:yuyunshize
- 中微子代理(neutrino-proxy):一款基於netty的開源的內網穿透神器
- 中微子代理文件:https://dromara.gitee.io/neutrino-proxy
- 中微子代理倉庫:https://gitee.com/dromara/neutrino-proxy