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 右值引用使用场景和意义:移…

「前端+鸿蒙」核心技术HTML5+CSS3(二)

1、开发者文档 开发者文档通常由浏览器厂商或技术社区提供,包含有关Web技术(如HTML、CSS、JavaScript)的详细信息,API文档,以及最佳实践。例如,MDN Web Docs是一个广泛认可的开发者资源。 2、块级元素与行列元素 块级元素:在页面上占据整行的元素,如<div>、<…

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

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

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

目录 一、array.flat&#xff08;&#xff09;方法 1.1、array.flat&#xff08;&#xff09;的语法及使用 ①语法 ②返回值 ③用途 二、array.flatMap() 方法 2.1、array.flatMap()的语法及作用 ①语法 ②返回值 ③用途 三、array.flat&#xff08;&#xff09;与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()&#xff0c;它使用了装饰器 lru_cache()。…

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

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

Vue基础(4)组件基础

1. 导入 要使用一个子组件&#xff0c;需要在父组件中进行导入 <script setup> import MyComponent from ./MyComponent.vue </script><template><MyComponent /> </template>2. 传递 props 在使用 <script setup> 的单文件组件中&…

服务器内存不足该怎么办?

当服务器的物理内存使用率达到或者是接近百分之百时&#xff0c;会导致系统没有办法为新的进程或者是请求分配足够的内存空间&#xff0c;在这种情况下&#xff0c;服务器的性能很有可能会受到一定的影响&#xff0c;严重的会导致系统崩溃或者服务出现中断。 那我们面临服务器内…

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

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

TS-类型转换(显式)

1.将其他类型转换为布尔类型 要将其他类型转换为布尔类型&#xff0c;只需要将待转换的值传入Boolean()函数 var msg: string "ok"; var msgToBollean: boolean Boolean(msg); //得到trueBoolean()函数会判断传入的值是空值还是非空值。 若表示非空值&#xff0…

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

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

Python零基础-下【详细】

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

线程进阶-1 线程池

一.说一下线程池的执行原理 1.线程池的七大核心参数 &#xff08;1&#xff09;int corePoolSize&#xff1a;核心线程数。默认情况下核心线程会一直存活&#xff0c;当设置allowCoreThreadTimeout为true时&#xff0c;核心线程也会被超时回收。 &#xff08;2&#xff09;i…

Linux基础指令磁盘管理001

Linux磁盘管理涉及多个方面&#xff0c;包括硬盘分区、文件系统创建、挂载、检查磁盘空间、优化性能和维护等。今天我们讲一下磁盘的分区挂载&#xff0c;文件系统的创建。 操作系统 CentOS Stream 9 磁盘的分区 当我们新插入一块磁盘后&#xff0c;首先使用fdisk -l查看磁盘…

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

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

【评价类模型】熵权法

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

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

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