Go微服务: 封装nacos-sdk-go的v2版本与应用

概述

  • 基于前文:https://active.blog.csdn.net/article/details/139213323
  • 我们基于此SDK提供的API封装一个公共方法来用于生产环境

封装 nacos-sdk-go

  • 我们封装一个 nacos.go 文件, 这个是通用的工具库

    package commonimport ("fmt""github.com/nacos-group/nacos-sdk-go/v2/clients""github.com/nacos-group/nacos-sdk-go/v2/clients/config_client""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/model""github.com/nacos-group/nacos-sdk-go/v2/vo"
    )// 定义常量和一些参数默认值
    var (clientParam              vo.NacosClientParam // 客户端参数缓存nacosIp                  = "127.0.0.1"nacosPort                = uint64(8848)nacosContextPath         = "/nacos"nacosNamespaceId         stringnacosTimeout             = uint64(5000)nacosNotLoadCacheAtStart = truenacosLogDir              = "nacos/log"nacosCacheDir            = "nacos/cache"nacosLogLevel            = "debug"
    )// 结构体
    type NacosParams struct {NacosIp                  stringNacosPort                uint64NacosContextPath         stringNacosNamespaceId         stringNacosTimeoutMs           uint64NacosNotLoadCacheAtStart boolNacosLogDir              stringNacosCacheDir            stringNacosLogLevel            string
    }// nacos参数实例
    var nacosParams NacosParams = NacosParams{NacosIp:                  nacosIp,NacosPort:                nacosPort,NacosContextPath:         nacosContextPath,NacosNamespaceId:         nacosNamespaceId,NacosTimeoutMs:           nacosTimeout,NacosNotLoadCacheAtStart: nacosNotLoadCacheAtStart,NacosLogDir:              nacosLogDir,NacosCacheDir:            nacosCacheDir,NacosLogLevel:            nacosLogLevel,
    }// InitConfig 初始化配置,允许通过函数参数修改默认配置
    func InitNacosParams(paramsModifier func(*NacosParams)) {if paramsModifier != nil {paramsModifier(&nacosParams)}
    }// 获取当前参数
    func GetNacosCurrentParams() NacosParams {return nacosParams
    }// 获取 nacos客户端参数
    func getNacosClientParam() vo.NacosClientParam {// 缓存配置参数if clientParam.ClientConfig != nil {return clientParam}// create ServerConfigsc := []constant.ServerConfig{*constant.NewServerConfig(nacosParams.NacosIp, nacosParams.NacosPort, constant.WithContextPath(nacosParams.NacosContextPath)),}// create ClientConfigcc := *constant.NewClientConfig(constant.WithNamespaceId(nacosParams.NacosNamespaceId),constant.WithTimeoutMs(nacosParams.NacosTimeoutMs),constant.WithNotLoadCacheAtStart(nacosParams.NacosNotLoadCacheAtStart),constant.WithLogDir(nacosParams.NacosLogDir),constant.WithCacheDir(nacosParams.NacosCacheDir),constant.WithLogLevel(nacosParams.NacosLogLevel),)clientParam = vo.NacosClientParam{ClientConfig:  &cc,ServerConfigs: sc,}return clientParam
    }// 获取 NacosNamingClient
    func getNacosNamingClient() (naming_client.INamingClient, error) {return clients.NewNamingClient(getNacosClientParam())
    }// 获取 NacosConfigClient
    func getNacosConfigClient() (config_client.IConfigClient, error) {return clients.NewConfigClient(getNacosClientParam())
    }// 注册服务功能
    func NacosRegisterServiceInstance(param vo.RegisterInstanceParam) (bool, error) {client, err := getNacosNamingClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return false, err}return client.RegisterInstance(param)
    }// 获取服务
    func NacosGetService(param vo.GetServiceParam) (model.Service, error) {client, err := getNacosNamingClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return model.Service{}, err}return client.GetService(param) // service, err
    }// 获取所有服务
    func NacosGetAllService(param vo.GetAllServiceInfoParam) (model.ServiceList, error) {client, err := getNacosNamingClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return model.ServiceList{}, err}return client.GetAllServicesInfo(param)
    }// 获取远程配置
    func NacosGetConfig(dataId string, group string) (string, error) {client, err := getNacosConfigClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return "", err}return client.GetConfig(vo.ConfigParam{DataId: dataId,Group:  group,})
    }// 搜索配置文件
    func NacosSearchConfig(params vo.SearchConfigParam) (*model.ConfigPage, error) {client, err := getNacosConfigClient()if err != nil {fmt.Println("NacosGetConfig Error", err.Error())return nil, err}return client.SearchConfig(params)
    }// 监听远程配置改动 回调函数类型
    type ConfigChangeListener func(namespace, group, dataId, data string)// 监听远程配置改动
    func NacosListenConfigWithCallback(dataId, group string, onChange ConfigChangeListener) error {client, err := getNacosConfigClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return err}err = client.ListenConfig(vo.ConfigParam{DataId: dataId,Group:  group,OnChange: func(namespace, group, dataId, data string) {// 当配置变更时,调用传入的回调函数onChange(namespace, group, dataId, data)},})return err
    }
    
    • 可以看到,上述集成了服务和配置两大类API
    • 服务
      • 注册服务
      • 获取服务
      • 获取所有服务
    • 配置
      • 获取远程配置
      • 搜索配置文件
      • 监听远程配置改动回调
    • 其他未实现封装
      • 比如:批量注册服务,注销服务,更新服务
      • 比如:选择所有实例,选择实例,选择健康实例,订阅,取消订阅
      • 比如:发布配置,删除配置,取消监听配置
      • 后续可以根据官方提供的其他api继续添加
  • 源码仓库:https://gitee.com/go-micro-services/common/blob/master/nacos.go

应用封装


1 )概述

  • 这里,我们应用在一个客户端,比如一个网关中
  • 这里使用gin框架+go-micro来实现封装的sdk

2 )目录结构

gitee.com/go-micro-services/nacos-go-micro-gin├── conf                                    # 当前位置文件│     └── conf.go├── routers                                 # 路由│     └── router.go├── controllers                             # 控制器│     └── api.go├── nacos                                   # nacos目录,后续生成,此文件写入 .gitignore│     ├── cache│     └── log├── main.go├── go.mod└── .gitignore

3 ) 源码

  • 仓库地址:https://gitee.com/go-micro-services/nacos-go-micro-gin

3.1 conf/conf.go

package confvar (NacosIp                  = "127.0.0.1"NacosPort                = uint64(8848)NacosTimeoutMs           = uint64(5000)NacosContextPath         = "/nacos"NacosNamespaceId         = "ff2e8758-33c1-4a88-8005-142cbee91be9" // 这个是配置命名空间后生成的NacosLogDir              = "nacos/log"NacosCacheDir            = "nacos/cache"NacosLogLevel            = "debug"NacosServiceName         = "nacos-go-micro-gin"NacosGroupName           = "dd"NacosNotLoadCacheAtStart = trueNacosMetadata            = map[string]string{"idc": "shanghai"}NacosDataId              = "test.json" // 这个是自己在nacos后台自己配置的NacosGroup               = "tt"        // 同上
)
  • 这里做了一个简单的通用配置,一般要拆分环境来管理
  • 这里做一个简单的示例

3.2 routers/router.go

package routersimport ("gitee.com/go-micro-services/nacos-go-micro-gin/controllers""github.com/gin-gonic/gin"
)func RoutersInit(r *gin.Engine) {rr := r.Group("/"){rr.GET("", controllers.ApiController{}.Index)rr.GET("/service", controllers.ApiController{}.FindService)rr.GET("/getConfig", controllers.ApiController{}.GetConfig)rr.GET("/searchConfig", controllers.ApiController{}.SearchConfig)}
}
  • 上面定义了4个路由,分别对应
    • /
    • /service
    • /getConfig
    • /searchConfig

3.3 controllers/api.go

package controllersimport ("encoding/json""net/http""strings""gitee.com/go-micro-services/common""gitee.com/go-micro-services/nacos-go-micro-gin/conf""github.com/gin-gonic/gin""github.com/nacos-group/nacos-sdk-go/v2/model""github.com/nacos-group/nacos-sdk-go/v2/vo"
)var statusOK = http.StatusOK
var statusBadRequest = http.StatusBadRequesttype ApiController struct{}func (con ApiController) Index(c *gin.Context) {params := vo.GetAllServiceInfoParam{GroupName: conf.NacosGroupName,PageNo:    1,PageSize:  10,}list, err := common.NacosGetAllService(params)// 错误处理if err != nil {// 错误处理c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 正常响应c.JSON(statusOK, list)
}func (con ApiController) FindService(c *gin.Context) {params := vo.GetServiceParam{ServiceName: conf.NacosServiceName,GroupName:   conf.NacosGroupName,}list, err := common.NacosGetService(params)// 错误处理if err != nil {// 错误处理c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 正常响应c.JSON(statusOK, list)
}func (con ApiController) GetConfig(c *gin.Context) {content, err := common.NacosGetConfig(conf.NacosDataId, conf.NacosGroup)// 错误处理if err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}var contentJson map[string]interface{}// 解码JSON字符串到maperr = json.Unmarshal([]byte(content), &contentJson)// 错误处理if err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 正常响应c.JSON(statusOK, contentJson)
}func (con ApiController) SearchConfig(c *gin.Context) {// 构造搜索参数params := vo.SearchConfigParam{Search:   "blur",DataId:   conf.NacosDataId,Group:    conf.NacosGroup,PageNo:   1,PageSize: 10,}// 调用接口获得结果var currentPage *model.ConfigPagevar err errorif currentPage, err = common.NacosSearchConfig(params); err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 格式转化var jsonBytes []byteif jsonBytes, err = json.Marshal(currentPage); err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 处理特殊字符,这里性能会有影响,可以用一个循环加一个Map来进行替换,而非每次 ReplaceAllstr := strings.ReplaceAll(string(jsonBytes), " ", "")str = strings.ReplaceAll(str, "\\n", "")str = strings.ReplaceAll(str, "\\", "")str = strings.ReplaceAll(str, `"{`, "{")str = strings.ReplaceAll(str, `}"`, "}")// 转换成 jsonvar result map[string]interface{}if err = json.Unmarshal([]byte(str), &result); err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}c.JSON(statusOK, result)
}
  • 这是对应上述4个路由的四个控制器的处理

3.4 main.go

package mainimport ("fmt""gitee.com/go-micro-services/common""gitee.com/go-micro-services/nacos-go-micro-gin/conf""gitee.com/go-micro-services/nacos-go-micro-gin/routers""github.com/gin-gonic/gin""github.com/nacos-group/nacos-sdk-go/v2/vo""go-micro.dev/v4/web"
)func init() {// 1. 参数初始化initNacosParams()// 2. 注册regNacos()// 3. 监听listenNacosConfig()
}// 参数初始化
func initNacosParams() {// 初始化配置,并在过程中修改默认值common.InitNacosParams(func(cfg *common.NacosParams) {cfg.NacosIp = conf.NacosIpcfg.NacosPort = conf.NacosPortcfg.NacosNamespaceId = conf.NacosNamespaceIdcfg.NacosLogLevel = conf.NacosLogLevel})// 如果需要,可以随时通过GetCurrentConfig获取配置副本currentConfig := common.GetNacosCurrentParams()fmt.Printf("Retrieved Config - Service Name: %s, Port: %d\n", currentConfig.NacosIp, currentConfig.NacosPort)
}// 注册
func regNacos() {_, err := common.NacosRegisterServiceInstance(vo.RegisterInstanceParam{Ip:          conf.NacosIp,Port:        conf.NacosPort,ServiceName: conf.NacosServiceName,GroupName:   conf.NacosGroupName,// ClusterName: "cluster-a",Weight:    10,Enable:    true,Healthy:   true,Ephemeral: true,Metadata:  conf.NacosMetadata,})if err != nil {fmt.Println("注册发生错误: ", err.Error())}
}// 监听配置改动
func listenNacosConfig() {var namespace, group, dataId stringerr := common.NacosListenConfigWithCallback(conf.NacosDataId, conf.NacosGroup, func(namespace, group, dataId, data string) {namespace = namespacegroup = groupdataId = dataIdfmt.Println("Config changed. Namespace: %s, Group: %s, DataId: %s, Content: %s", namespace, group, dataId, data)})if err != nil {fmt.Println("Failed to listen config for Namespace: %s, DataId: %s, Group: %s. Error: %v", namespace, dataId, group, err)}
}func main() {ginRouter := gin.Default()routers.RoutersInit(ginRouter)srv := web.NewService(web.Metadata(map[string]string{"version": "latest"}),web.Handler(ginRouter),      // 服务路由web.Address("0.0.0.0:9999"), // 服务端口)srv.Run()
}
  • 这里的main.go主要关注的是上面的 init 函数中的nacos配置
  • 这里演示的是客户端,当然服务端也是使用封装后的sdk

演示效果


1 )手动配置的配置文件

2 ) 注册了的服务

3 )API 应用的路由相关返回

其他

  • 在 go-micro中,有 nacos 的相关插件,它也是自己的封装
  • 但是,在使用的时候,可能不能完全满足所有的nacos的接口实现
  • 所以,我个人推荐基于官方提供的api 自行进行封装和扩展,从而不被 go-micro 限制
  • 毕竟,框架的使用会有一个通用的问题就是虽然使用方便,但扩展修改可能会受其限制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/340328.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux下的Git应用及配置

1、卸载 2、安装 3、创建并初始化 4、配置 (附加删除语句) 5、查看(tree .git/) 6、增加和提交 7、打印日志 8、验证已操作工作

【机器学习】朴素贝叶斯算法及其应用探索

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 朴素贝叶斯算法及其应用探索引言1. 朴素贝叶斯基本概念1.1 贝叶斯定理回顾1.2 朴…

面试题:说一下 http 报文都有哪些东西?

面试题:说一下 http 报文都有哪些东西? HTTP 是传输超文本(实际上除了 HTML,可以传输任何类型的文件,如视频、音频、文本等)的协议,是一组用于浏览器-服务器之间数据传输的规则。 HTTP 位于 OS…

量化投资分析平台 迅投 QMT(二)

量化投资分析平台 迅投 QMT [迅投 QMT](https://www.xuntou.net/?user_code7NYs7O)我目前在使用如何获取数据上代码历史帖子 迅投 QMT 我目前在使用 两个月前(2024年4月)迅投和CQF有一个互动的活动,进行了平台的一个网上路演,刚…

简单小游戏制作

控制台基础设置 //隐藏光标 Console.CursorVisible false; //通过两个变量来存储舞台的大小 int w 50; int h 30; //设置舞台(控制台)的大小 Console.SetWindowSize(w, h); Console.SetBufferSize(w, h);多个场景 int nowSceneID 1; while (true) …

从0开始学人工智能测试节选:Spark -- 结构化数据领域中测试人员的万金油技术(三)

分布式计算原理 分布式计算的原理总结一句话就是:分而治之。 把数据分片,存在不同的机器中,解决数据存储的压力。客户端和服务端之间通过相关协议来自动的完成在不同的机器之间进行数据的存取,用户并不感知数据的物理存储结构。 用…

大模型Prompt-Tuning技术入门

Prompt-Tuning方法 1 NLP任务四种范式 目前学术界一般将NLP任务的发展分为四个阶段,即NLP四范式: 第一范式:基于「传统机器学习模型」的范式,如TF-IDF特征朴素贝叶斯等机器算法;第二范式:基于「深度学习模…

python小练习03

1.绘制奥运五环旗 #奥运五环的绘制 import turtle as t t.pensize(3) t.speed(0) def draw_circles():i0while i <4:args [[-60,0,"blue"],[0,0,"black"],[60,0,"red"],[-30,-30,"yellow"],[30,-30,"green"]]#定义一个…

双指针解题

验证回文数&#xff08;验证回文数-CSDN博客&#xff09;和判断在子序列&#xff08;判断子序列-CSDN博客&#xff09;已经在之前进行了计算&#xff0c;今天有三个新的双指针问题&#xff1a; 两数之和II—输入有序数组 给你一个下标从 1 开始的整数数组 numbers &#xff0…

ZL-GL-4离体组织灌流系统测试在恒温条件下离体标本的肌张拉力

简单介绍&#xff1a; 离体组织灌流系统为生理实验及药理实验提供恒温环境&#xff0c;在麦氏浴皿内加养液同时能通氧&#xff0c;测试在恒温条件下离体标本的肌张拉力&#xff0c;离体组织灌流系统具有进气口,配备微调固定器,省时省力,并提高了实验效率,同时可方便串联恒温供水…

【银河麒麟V10服务器OS-系统根分区扩容】指导教程手册

【银河麒麟V10服务器OS-系统根分区扩容】指导教程手册 环境信息&#xff1a;VMware虚拟软件16.0 首先查看KylinOS服务器版本&#xff1a;nkvers 备注&#xff1a; (Tercel) 版本是 V10 SP1 版本&#xff0c; (Sword) 版本是 V10 SP2 版本&#xff0c; (Lance) 版本是 V10 …

超声波清洗机哪家好一点?四大顶级高分超声波清洗机专业推荐

在日常生活中&#xff0c;我们每天都在与灰尘和污渍作斗争&#xff0c;尤其是对于那些细小、精密的物品&#xff0c;如眼镜。眼镜不仅是视力矫正的工具&#xff0c;更是我们个人形象的一部分。一副干净、明亮的眼镜可以让我们的视线更加清晰。因为保持眼镜的清洁是一件很重要的…

初始操作系统

概念&#xff1a; 1.系统资源的管理者&#xff1a;实质控制和管理整个计算机系统的硬件和软件资源&#xff0c;并合理地组织调度计算机地工作和资源的分配 2.向上层提供方便易用的服务&#xff1a;以提供给用户和其他软件方便接口和环境 封装思想&#xff1a;操作系统把一些丑…

进阶 RocketMQ - 消息存储-一张图掌握核心要点

看了很多遍源码整理的 一张图进阶 RocketMQ 图片&#xff0c;关于 RocketMQ 你只需要记住这张图&#xff01; 消息传递责任已移交至Broker&#xff0c;接下来如何处理&#xff1f;首先&#xff0c;我们需要确保消息的持久化&#xff0c;避免因宕机导致的数据丢失。那么&#xf…

电商API商品数据采集接口||助力电商企业采集商品大数据提高开发效率

提高开发效率&#xff1a;电商API接口允许不同的应用程序之间高效地进行交互&#xff0c;节省了大量的人力物力成本&#xff0c;使得开发者可以将更多时间和精力集中于自身的核心业务。 增加数据安全性&#xff1a;通过对数据进行安全加密&#xff0c;API接口实现了对数据的保护…

IP地址开启HTTPS方法

可以使用IP地址申请SSL证书&#xff0c;申请之前必须是公网IP地址&#xff0c;不支持内网IP地址申请。 申请过程需要确定IP地址外网可以访问&#xff0c;这里特别注意只是申请过程中可以访问。访问验证过程必须采取80端口、443端口两者选择1个&#xff0c;不可以用其它端口进行…

[C/C++]_[初级]_[在Windows和macOS平台上导出动态库的一些思考]

场景 最近看了《COM本质论》里关于如何设计基于抽象基类作为二进制接口,把编译器和链接器的实现隐藏在这个二进制接口中,从而使用该DLL时不需要重新编译。在编译出C接口时,发现接口名直接是函数名,比如BindNativePort,怎么不是_BindNativePort?说明 VC++导出的函数默认是使…

javaweb——js

JavaScript是一种网页脚本语言。JavaScript代码可以很容易的嵌入到HTML页面中。 js引入 JavaScript嵌入到HTML页面中 <body><script>alert("Hello JS")</script> </body>再HTML页面中插入外部脚本JavaScript <body><script src&…

三、基于图像分类预训练编码及图神经网络的预测模型 【框图+源码】

背景&#xff1a; 抽时间补充&#xff0c;先挖个坑。 一、模型结构 二、源码

【2023百度之星初赛】跑步,夏日漫步,糖果促销,第五维度,公园,新材料,星际航行,蛋糕划分

目录 题目&#xff1a;跑步 思路&#xff1a; 题目&#xff1a;夏日漫步 思路&#xff1a; 题目&#xff1a;糖果促销 思路&#xff1a; 题目&#xff1a;第五维度 思路&#xff1a; 题目&#xff1a;公园 思路&#xff1a; 新材料 思路&#xff1a; 星际航行 思路…