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}// 处理特殊字符str := 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.mzph.cn/web/19773.shtml

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

相关文章

使用LeanCloud平台的即时通讯

LeanCloud 是领先的 Serverless 云服务,为产品开发提供强有力的后端支持,旨在帮助开发者降低研发、运营维护等阶段投入的精力和成本。 LeanCloud 整合了各项服务,让开发者能够聚焦在核心业务上,为客户创造更多价值。 *即时通讯 …

基于安卓的虫害识别软件设计--(1)模型训练与可视化

引言 简介:使用pytorch框架,从模型训练、模型部署完整地实现了一个基础的图像识别项目计算资源:使用的是Kaggle(每周免费30h的GPU) 1.创建名为“utils_1”的模块 模块中包含:训练和验证的加载器函数、训练…

【Python爬虫--scrapy+selenium框架】超详细的Python爬虫scrapy+selenium框架学习笔记(保姆级别的,非常详细)

六,selenium 想要下载PDF或者md格式的笔记请点击以下链接获取 python爬虫学习笔记点击我获取 Scrapyselenium详细学习笔记点我获取 Python超详细的学习笔记共21万字点我获取 1,下载配置 ## 安装: pip install selenium## 它与其他库不同…

【C++】C++11新特性:列表初始化、声明、新容器、右值引用、万能引用和完美转发

目录 一、列表初始化 1.1 { } 初始化 1.2 std::initializer_list 二、声明 2.1 auto 2.2 decltype 2.3 nullptr 三、新容器 四、右值引用和移动语义 4.1 左值和左值引用 4.2 右值和右值引用 4.3 左值引用与右值引用比较 4.4 右值引用使用场景和意义:移…

万字长文深度解析Agent反思工作流框架Reflexion下篇:ReflectionAgent workflow

在前文[LLM-Agents]万字长文深度解析Agent反思工作流框架Reflexion中篇:React中,我们详细解析了ReactAgent的工作流程,而本文则将在此基础上探讨反思技巧的应用。之前的文章中[LLM-Agents]反思Reflection 工作流我们已经对反思技巧进行了探讨…

多维数组操作,不要再用遍历循环foreach了!来试试数组展平的小妙招!array.flat()用法与array.flatMap() 用法及二者差异详解

目录 一、array.flat()方法 1.1、array.flat()的语法及使用 ①语法 ②返回值 ③用途 二、array.flatMap() 方法 2.1、array.flatMap()的语法及作用 ①语法 ②返回值 ③用途 三、array.flat()与a…

CLIP 源码分析:simple_tokenizer.py

tokenizer的含义 from .clip import *引入头文件时为什么有个. 正文 import gzip import html import os from functools import lru_cacheimport ftfy import regex as re# 上面的都是头文件# 这段代码定义了一个函数 default_bpe(),它使用了装饰器 lru_cache()。…

一维时间序列信号的改进小波降噪方法(MATLAB R2021B)

目前国内外对于小波分析在降噪方面的方法研究中,主要有小波分解与重构法降噪、小波阈值降噪、小波变换模极大值法降噪等三类方法。 (1)小波分解与重构法降噪 早在1988 年,Mallat提出了多分辨率分析的概念,利用小波分析的多分辨率特性进行分…

DAQmx Connect Terminals (VI) 信号路由作用及意义

DAQmx Connect Terminals是一个LabVIEW虚拟仪器(VI),用于配置和连接数据采集系统中的物理终端或虚拟终端。这一功能在配置复杂的数据采集(DAQ)系统时非常重要,因为它允许用户在不改变硬件连接的情况下&…

Python——Selenium快速上手+方法(一站式解决问题)

目录 前言 一、Selenium是什么 二、Python安装Selenium 1、安装Selenium第三方库 2、下载浏览器驱动 3、使用Python来打开浏览器 三、Selenium的初始化 四、Selenium获取网页元素 4.1、获取元素的实用方法 1、模糊匹配获取元素 & 联合多个样式 2、使用拉姆达表达式 3、加上…

Python零基础-下【详细】

接上篇继续: Python零基础-中【详细】-CSDN博客 目录 十七、网络编程 1、初识socket (1)socket理解 (2)图解socket (3)戏说socket (4)网络服务 (5&a…

实战经验分享之移动云快速部署Stable Diffusion SDXL 1.0

本文目录 前言产品优势部署环境准备模型安装测试运行 前言 移动云是中国移动面向政府、企业和公众的新型资源服务。 客户以购买服务的方式,通过网络快速获取虚 拟计算机、存储、网络等基础设施服务;软件开发工具、运行环境、数据库等平台服务&#xff1…

【评价类模型】熵权法

1.客观赋权法: 熵权法是一种客观求权重的方法,所有客观求权重的模型中都要有以下几步: 1.正向化处理: 极小型指标:取值越小越好的指标,例如错误率、缺陷率等。 中间项指标:取值在某个范围内较…

[ubuntu18.04]搭建mptcp测试环境说明

MPTCP介绍 Multipath TCP — Multipath TCP -- documentation 2022 documentation 安装ubuntu18.04,可以使用虚拟机安装 点击安装VMware Tool 桌面会出现如下图标 双击打开VMware Tools,复制如下图所示的文件到Home目录 打开终端,切换到管…

[Linux]重定向

一、struct file内核对象 struct file是在内核中创建,专门用来管理被打开文件的结构体。struct file中包含了打开文件的所有属性,文件的操作方法集以及文件缓冲区(无论读写,我们都需要先将数据加载到文件缓冲区中。)等…

基于JSP的高校二手交易平台

开发语言:Java 数据库:MySQL 技术:JSP技术 工具:浏览器(如360浏览器、谷歌浏览器、QQ浏览器等)、MySQL数据库 系统展示 系统功能界面 用户注册与登录界面 个人中心界面 商品信息界面 摘要 本文研究了高…

为何懂行的人都在选海信Mini LED?

今年的618大促比往年来得要更早一些。纵览各电商平台的电视产品,能发现Mini LED电视的出镜率很高,成了各大品牌的主推产品。 对于什么样的Mini LED更值得买,各品牌都有自己的说辞。因为缺乏科学系统的选购标准,消费者容易在各方说…

【Qt】【模型-视图架构】代理模型示例

文章目录 1. 基本排序/过滤模型Basic Sort/Filter Model Example2. 自定义排序/过滤模型Custom Sort/Filter Model ExampleFilterLineEdit类定义及实现MySortFilterProxyModel类定义及实现 1. 基本排序/过滤模型Basic Sort/Filter Model Example 官方提供的基本排序/过滤模型示…

docker镜像体积优化攻略参考—— 筑梦之路

简单介绍 镜像的本质是镜像层和运行配置文件组成的压缩包,构建镜像是通过运行 Dockerfile 中的 RUN 、COPY 和 ADD 等指令生成镜像层和配置文件的过程。 和镜像体积大小有关的关键点: RUN、COPY 和 ADD 指令会在已有镜像层的基础上创建一个新的镜像层&…

【数据结构】详解二叉树

文章目录 1.树的结构及概念1.1树的概念1.2树的相关结构概念1.3树的表示1.4树在实际中的应用 2.二叉树的结构及概念2.1二叉树的概念2.2特殊的二叉树2.2.1满二叉树2.2.2完全二叉树 2.3 二叉树的性质2.4二叉树的存储结构2.4.1顺序结构2.4.2链表结构 1.树的结构及概念 1.1树的概念…