脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Golang - Golang基于泛化调用与Nacos实现Dubbo代理

Golang基于泛化调用与Nacos实现Dubbo代理

2023-04-06 17:34cipher Golang

这篇文章主要为大家详细介绍了Golang如何基于泛化调用与Nacos实现Dubbo代理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前言

由于工作中使用的 rpc 框架是 dubbo,经常需要调试不同环境的 dubbo 接口,例如本地环境、开发环境和测试环境。而为了统一管理 http 接口和 dubbo 接口,希望使用统一的调试工具,例如 PostMan 或 ApiPost 等,因此萌生了开发一个 dubbo 的 http 代理工具的念头。

准备

由于是通用的 dubbo 代理,因此肯定需要使用泛化调用。而我们使用的注册中心是 nacos,因此也需要使用 nacos-sdk 来获取 provider 的实例信息。

实现

项目结构


├── dubbo/                 
│    ├─ generic.go   # 泛化调用 dubbo 接口
│    ├─ models.go    # 数据模型
│    └─ nacos.go     # 获取 nacos 元信息
├── web/                       
│    └─ server.go    # 对外 http 接口

├── main.go          # main 入口函数
└── go.mod           # 模块描述文件

go.mod

?
1
2
3
4
5
6
7
8
9
10
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
)

返回数据格式

dubbo/models.go:

?
1
2
3
4
5
6
type DataResult struct {
    Env     string `json:"env,omitempty"// 当前调用环境
    Code    string `json:"code,omitempty"` // 返回结果码
    Data    any    `json:"data,omitempty"` // 返回结果
    Message string `json:"message,omitempty"` // 返回消息
}

获取 nacos 元信息

根据环境创建 nacos client

?
1
2
3
4
5
6
7
8
9
10
11
12
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
}

获取服务实例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
}

泛化调用

dubbo root 配置

?
1
2
3
4
5
6
7
8
9
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()

泛化调用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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行要根据业务自身的返回数据格式包装结果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
    这个例子的 dubbo 调用都会返回通过的结构:
    {
        "code": "",
        "message": "",
        "data": // 真正的调用结果
    }
*/
rawResult := raw.(map[interface{}]interface{})
result := DataResult{
    Code:    rawResult["code"].(string),
    Message: rawResult["message"].(string),
    Data:    rawResult["data"],
}

完整代码

dubbo/generic.go:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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 服务

dubbo/generic.go:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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"))
}

启动

main.go:

?
1
2
3
4
5
6
7
package main
 
import "dubbo-proxy/web"
 
func main() {
    web.Run()
}

效果

Golang基于泛化调用与Nacos实现Dubbo代理

以上就是Golang基于泛化调用与Nacos实现Dubbo代理的详细内容,更多关于Golang Dubbo代理的资料请关注服务器之家其它相关文章!

原文链接:https://www.ciphermagic.cn/go-dubbo-proxy.html

延伸 · 阅读

精彩推荐
  • GolangGo到底能不能实现安全的双检锁(推荐)

    Go到底能不能实现安全的双检锁(推荐)

    这篇文章主要介绍了Go到底能不能实现安全的双检锁,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友...

    波斯马7802022-10-11
  • GolangGolang数组的传递详解

    Golang数组的传递详解

    今天小编就为大家分享一篇关于Golang数组的传递详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    benben_20159482020-05-23
  • Golang一文带你了解Go语言标准库math和rand的常用函数

    一文带你了解Go语言标准库math和rand的常用函数

    这篇文章主要为大家详细介绍了Go语言标准库math和rand中的常用函数,文中的示例代码讲解详细, 对我们学习Go语言有一定的帮助,感兴趣的小伙伴可以了解...

    陈明勇10442022-12-19
  • GolangGo每日一库之dateparse处理时间

    Go每日一库之dateparse处理时间

    不管什么时候,处理时间总是让人头疼的一件事情。今天要介绍的dateparse实现解析日期时间格式的字符串。具有一定的参考价值,感兴趣的小伙伴们可以参...

    darjun12202021-08-13
  • GolangGo语言Mock使用基本指南详解

    Go语言Mock使用基本指南详解

    这篇文章主要介绍了Go语言Mock使用基本指南详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面...

    Destiny池鱼3872020-07-20
  • Golang从源码的角度看Go语言Flag库如何解析命令行参数!

    从源码的角度看Go语言Flag库如何解析命令行参数!

    Parse的代码里用到了一个,CommandLine共享变量,这就是内部库维护的FlagSet,所有的参数都会插到里面的变量地址向地址的指向赋值绑定。...

    机智的程序员小熊10742021-08-11
  • Golang为什么要避免在 Go 中使用 ioutil.ReadAll?

    为什么要避免在 Go 中使用 ioutil.ReadAll?

    本篇文章从一个问题入手,重点研究了 ioutil.ReadAll 函数。主要原因是在小数据量的情况下,这个函数并没有什么问题,但当数据量大时,它就变成了一颗定...

    AlwaysBeta5092022-01-04
  • Golanggo浮点数转字符串保留小数点后N位的完美解决方法

    go浮点数转字符串保留小数点后N位的完美解决方法

    这篇文章主要介绍了go浮点数转字符串保留小数点后N位解决办法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可...

    iuoui37342020-06-09