Golang基于泛化調(diào)用與Nacos實(shí)現(xiàn)Dubbo代理
前言
由于工作中使用的 rpc 框架是 dubbo,經(jīng)常需要調(diào)試不同環(huán)境的 dubbo 接口,例如本地環(huán)境、開發(fā)環(huán)境和測(cè)試環(huán)境。而為了統(tǒng)一管理 http 接口和 dubbo 接口,希望使用統(tǒng)一的調(diào)試工具,例如 PostMan 或 ApiPost 等,因此萌生了開發(fā)一個(gè) dubbo 的 http 代理工具的念頭。
準(zhǔn)備
由于是通用的 dubbo 代理,因此肯定需要使用泛化調(diào)用。而我們使用的注冊(cè)中心是 nacos,因此也需要使用 nacos-sdk 來獲取 provider 的實(shí)例信息。
實(shí)現(xiàn)
項(xiàng)目結(jié)構(gòu)
│
├── dubbo/
│ ├─ generic.go # 泛化調(diào)用 dubbo 接口
│ ├─ models.go # 數(shù)據(jù)模型
│ └─ nacos.go # 獲取 nacos 元信息
├── web/
│ └─ server.go # 對(duì)外 http 接口
│
├── main.go # main 入口函數(shù)
└── go.mod # 模塊描述文件
go.mod
module dubbo-proxy go 1.20 require ( dubbo.apache.org/dubbo-go/v3 v3.0.5 github.com/apache/dubbo-go-hessian2 v1.12.0 github.com/gin-gonic/gin v1.9.0 github.com/nacos-group/nacos-sdk-go/v2 v2.1.2 )
返回?cái)?shù)據(jù)格式
dubbo/models.go
:
type DataResult struct { Env string `json:"env,omitempty"` // 當(dāng)前調(diào)用環(huán)境 Code string `json:"code,omitempty"` // 返回結(jié)果碼 Data any `json:"data,omitempty"` // 返回結(jié)果 Message string `json:"message,omitempty"` // 返回消息 }
獲取 nacos 元信息
根據(jù)環(huán)境創(chuàng)建 nacos client
func buildClient(env string, serverCfgs []constant.ServerConfig) naming_client.INamingClient { client, _ := clients.NewNamingClient( vo.NacosClientParam{ ClientConfig: constant.NewClientConfig( constant.WithNamespaceId(env), constant.WithNotLoadCacheAtStart(true), ), ServerConfigs: serverCfgs, }, ) return client }
獲取服務(wù)實(shí)例
func SelectInstance(env, servName string) (string, bool) { cli, ok := cliMap[env] if !ok { return "client not found from " + env, false } instances, e := cli.SelectInstances(vo.SelectInstancesParam{ ServiceName: fmt.Sprintf("providers:%s:1.0.0:", servName), HealthyOnly: true, }) if e != nil { return "instance not found, " + e.Error(), false } if len(instances) <= 0 { return "instance not found", false } return fmt.Sprintf("dubbo://%s:%d", instances[0].Ip, instances[0].Port), true }
完整代碼
dubbo/nacos.go
:
package dubbo import ( "fmt" "github.com/nacos-group/nacos-sdk-go/v2/clients" "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" "github.com/nacos-group/nacos-sdk-go/v2/common/constant" "github.com/nacos-group/nacos-sdk-go/v2/vo" ) var cliMap = make(map[string]naming_client.INamingClient) func init() { serverCfgs := []constant.ServerConfig{ *constant.NewServerConfig("127.0.0.1", 6801, constant.WithContextPath("/nacos")), } cliMap["local"] = buildClient("local", serverCfgs) cliMap["dev"] = buildClient("develop", serverCfgs) cliMap["test"] = buildClient("test", serverCfgs) } func buildClient(env string, serverCfgs []constant.ServerConfig) naming_client.INamingClient { client, _ := clients.NewNamingClient( vo.NacosClientParam{ ClientConfig: constant.NewClientConfig( constant.WithNamespaceId(env), constant.WithNotLoadCacheAtStart(true), ), ServerConfigs: serverCfgs, }, ) return client } func SelectInstance(env, servName string) (string, bool) { cli, ok := cliMap[env] if !ok { return "client not found from " + env, false } instances, e := cli.SelectInstances(vo.SelectInstancesParam{ ServiceName: fmt.Sprintf("providers:%s:1.0.0:", servName), HealthyOnly: true, }) if e != nil { return "instance not found, " + e.Error(), false } if len(instances) <= 0 { return "instance not found", false } return fmt.Sprintf("dubbo://%s:%d", instances[0].Ip, instances[0].Port), true }
泛化調(diào)用
dubbo root 配置
var dubboRoot = cfg.NewRootConfigBuilder().SetProtocols(map[string]*cfg.ProtocolConfig{ dubbo.DUBBO: { Params: map[string]interface{}{ "getty-session-param": map[string]interface{}{ "max-msg-len": 1024000, }, }, }, }).Build()
泛化調(diào)用
func GenericInvoke(iName, method, env string, req []byte) DataResult { instance, ok := SelectInstance(env, iName) if !ok { return DataResult{ Code: "ERROR", Message: instance, } } cfg.Load(cfg.WithRootConfig(dubboRoot)) refConf := cfg.ReferenceConfig{ InterfaceName: iName, Cluster: "failover", Protocol: dubbo.DUBBO, Generic: "true", Version: "1.0.0", URL: instance, } refConf.Init(dubboRoot) refConf.GenericLoad("dubbo-proxy") var args = utils.Unmarshal(req, &map[string]hessian.Object{}) raw, err := refConf.GetRPCService().(*generic.GenericService).Invoke(context.Background(), method, nil, []hessian.Object{args}) if err != nil { panic(err) } rawResult := raw.(map[interface{}]interface{}) result := DataResult{ Code: rawResult["code"].(string), Message: rawResult["message"].(string), Data: utils.ConvertAs(rawResult["data"], map[string]interface{}{}), } return result }
注意25-30
行要根據(jù)業(yè)務(wù)自身的返回?cái)?shù)據(jù)格式包裝結(jié)果:
/* 這個(gè)例子的 dubbo 調(diào)用都會(huì)返回通過的結(jié)構(gòu): { "code": "", "message": "", "data": // 真正的調(diào)用結(jié)果 } */ rawResult := raw.(map[interface{}]interface{}) result := DataResult{ Code: rawResult["code"].(string), Message: rawResult["message"].(string), Data: rawResult["data"], }
完整代碼
dubbo/generic.go
:
package dubbo import ( "context" "dubbo-proxy/utils" cfg "dubbo.apache.org/dubbo-go/v3/config" "dubbo.apache.org/dubbo-go/v3/config/generic" _ "dubbo.apache.org/dubbo-go/v3/imports" "dubbo.apache.org/dubbo-go/v3/protocol/dubbo" hessian "github.com/apache/dubbo-go-hessian2" ) var dubboRoot = cfg.NewRootConfigBuilder().SetProtocols(map[string]*cfg.ProtocolConfig{ dubbo.DUBBO: { Params: map[string]interface{}{ "getty-session-param": map[string]interface{}{ "max-msg-len": 1024000, }, }, }, }).Build() func GenericInvoke(iName, method, env string, req []byte) DataResult { instance, ok := SelectInstance(env, iName) if !ok { return DataResult{ Code: "ERROR", Message: instance, } } cfg.Load(cfg.WithRootConfig(dubboRoot)) refConf := cfg.ReferenceConfig{ InterfaceName: iName, Cluster: "failover", Protocol: dubbo.DUBBO, Generic: "true", Version: "1.0.0", URL: instance, } refConf.Init(dubboRoot) refConf.GenericLoad("dubbo-proxy") var args = utils.Unmarshal(req, &map[string]hessian.Object{}) raw, err := refConf.GetRPCService().(*generic.GenericService).Invoke(context.Background(), method, nil, []hessian.Object{args}) if err != nil { panic(err) } rawResult := raw.(map[interface{}]interface{}) result := DataResult{ Code: rawResult["code"].(string), Message: rawResult["message"].(string), Data: utils.ConvertAs(rawResult["data"], map[string]interface{}{}), } return result }
提供 http 服務(wù)
dubbo/generic.go
:
package web import ( "dubbo-proxy/dubbo" "github.com/gin-gonic/gin" "net/http" ) func Run() { router := gin.Default() router.POST("/:intf/:method", func(c *gin.Context) { intf := c.Param("intf") method := c.Param("method") env := c.Query("env") data, err := c.GetRawData() if err != nil { panic(err) } res := dubbo.GenericInvoke(intf, method, env, data) res.Env = env c.JSON(http.StatusOK, res) }) panic(router.Run(":7788")) }
啟動(dòng)
main.go
:
package main import "dubbo-proxy/web" func main() { web.Run() }
效果
以上就是Golang基于泛化調(diào)用與Nacos實(shí)現(xiàn)Dubbo代理的詳細(xì)內(nèi)容,更多關(guān)于Golang Dubbo代理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
GoFrame框架數(shù)據(jù)校驗(yàn)之校驗(yàn)對(duì)象校驗(yàn)結(jié)構(gòu)體
這篇文章主要為大家介紹了GoFrame框架數(shù)據(jù)校驗(yàn)之校驗(yàn)對(duì)象校驗(yàn)結(jié)構(gòu)體示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Go語言利用ffmpeg轉(zhuǎn)hls實(shí)現(xiàn)簡(jiǎn)單視頻直播
這篇文章主要為大家介紹了Go語言利用ffmpeg轉(zhuǎn)hls實(shí)現(xiàn)簡(jiǎn)單視頻直播,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04詳解go-micro微服務(wù)consul配置及注冊(cè)中心
這篇文章主要為大家介紹了go-micro微服務(wù)consul配置及注冊(cè)中心示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Go中使用gjson來操作JSON數(shù)據(jù)的實(shí)現(xiàn)
本文主要介紹了Go中使用gjson來操作JSON數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08淺析Go語言如何在select語句中實(shí)現(xiàn)優(yōu)先級(jí)
這篇文章主要為大家詳細(xì)介紹了Go語言如何在select語句中實(shí)現(xiàn)優(yōu)先級(jí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03