【Golang/nacos】nacos配置的增删查改,以及服务注册的golang实例及分析
前言
本文分析的实例来源于nacos在github上的开源仓库
nacos配置的增删查改
先具体来看一段代码,我将逐步分析每一段的作用
package mainimport ("fmt""time""github.com/nacos-group/nacos-sdk-go/clients""github.com/nacos-group/nacos-sdk-go/common/constant""github.com/nacos-group/nacos-sdk-go/vo"
)func main() {// 创建ServerConfigsc := []constant.ServerConfig{*constant.NewServerConfig("192.168.195.129", // Nacos服务器的IP地址8848, // Nacos服务器的端口号constant.WithContextPath("/nacos"), // 上下文路径),}// 创建ClientConfigcc := *constant.NewClientConfig(constant.WithNamespaceId("ace1b5fe-80c3-4fab-b89a-625f9ff41093"), // 命名空间IDconstant.WithTimeoutMs(5000), // 超时时间(毫秒)constant.WithNotLoadCacheAtStart(true), // 启动时不加载缓存constant.WithLogDir("/tmp/nacos/log"), // 日志目录constant.WithCacheDir("/tmp/nacos/cache"), // 缓存目录constant.WithLogLevel("debug"), // 日志级别constant.WithUsername("nacos"), // 用户名constant.WithPassword("nacos"), // 密码)// 创建配置客户端client, err := clients.NewConfigClient(vo.NacosClientParam{ClientConfig: &cc, // 客户端配置ServerConfigs: sc, // 服务器配置切片},)if err != nil {panic(err) // 如果创建客户端失败,程序终止并打印错误信息}// 发布配置_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data", // 配置的数据IDGroup: "test-group", // 配置的分组Content: "hello world!", // 配置的内容})if err != nil {fmt.Printf("PublishConfig err:%+v \n", err) // 如果发布配置失败,打印错误信息}_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data-2", // 第二个配置的数据IDGroup: "test-group", // 第二个配置的分组Content: "hello world!", // 第二个配置的内容})if err != nil {fmt.Printf("PublishConfig err:%+v \n", err) // 如果发布配置失败,打印错误信息}// 等待1秒,确保配置发布完成time.Sleep(1 * time.Second)// 获取配置content, err := client.GetConfig(vo.ConfigParam{DataId: "test-data", // 要获取的配置的数据IDGroup: "test-group", // 要获取的配置的分组})fmt.Println("GetConfig,config :" + content) // 打印获取到的配置内容// 监听配置变更err = client.ListenConfig(vo.ConfigParam{DataId: "test-data", // 要监听的配置的数据IDGroup: "test-group", // 要监听的配置的分组OnChange: func(namespace, group, dataId, data string) {fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) // 配置变更时打印信息},})if err != nil {fmt.Printf("ListenConfig err:%+v \n", err) // 如果监听失败,打印错误信息}err = client.ListenConfig(vo.ConfigParam{DataId: "test-data-2", // 第二个要监听的配置的数据IDGroup: "test-group", // 第二个要监听的配置的分组OnChange: func(namespace, group, dataId, data string) {fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) // 配置变更时打印信息},})if err != nil {fmt.Printf("ListenConfig err:%+v \n", err) // 如果监听失败,打印错误信息}// 等待1秒,确保监听配置生效time.Sleep(1 * time.Second)// 修改配置_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data", // 要修改的配置的数据IDGroup: "test-group", // 要修改的配置的分组Content: "test-listen", // 修改后的配置内容})if err != nil {fmt.Printf("PublishConfig err:%+v \n", err) // 如果修改配置失败,打印错误信息}_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data-2", // 第二个要修改的配置的数据IDGroup: "test-group", // 第二个要修改的配置的分组Content: "test-listen", // 第二个修改后的配置内容})if err != nil {fmt.Printf("PublishConfig err:%+v \n", err) // 如果修改配置失败,打印错误信息}// 等待2秒,确保配置修改被监听到time.Sleep(2 * time.Second)// 等待1秒time.Sleep(1 * time.Second)// 删除配置_, err = client.DeleteConfig(vo.ConfigParam{DataId: "test-data", // 要删除的配置的数据IDGroup: "test-group", // 要删除的配置的分组})if err != nil {fmt.Printf("DeleteConfig err:%+v \n", err) // 如果删除配置失败,打印错误信息}// 等待1秒,确保配置删除操作完成time.Sleep(1 * time.Second)// 取消监听配置变更err = client.CancelListenConfig(vo.ConfigParam{DataId: "test-data", // 要取消监听的配置的数据IDGroup: "test-group", // 要取消监听的配置的分组})if err != nil {fmt.Printf("CancelListenConfig err:%+v \n", err) // 如果取消监听失败,打印错误信息}// 搜索配置searchPage, _ := client.SearchConfig(vo.SearchConfigParam{Search: "blur", // 搜索模式,这里是模糊搜索DataId: "", // 数据ID,为空表示不指定Group: "", // 分组,为空表示不指定PageNo: 1, // 搜索的页码PageSize: 10, // 每页的大小})fmt.Printf("Search config:%+v \n", searchPage) // 打印搜索结果
}
Serverconfig
ServerConfig
主要用于配置Nacos服务器的信息。它告诉客户端如何连接到Nacos服务器,包括服务器的IP地址、端口号和上下文路径等。通过ServerConfig
,客户端可以找到并连接到Nacos服务器,这里以切片的形式,是为了可以保证多个选择,并且具有可扩展性。
sc := []constant.ServerConfig{*constant.NewServerConfig("192.168.195.129", // Nacos服务器的IP地址8848, // Nacos服务器的端口号constant.WithContextPath("/nacos"), // 上下文路径),
}
这段代码配置了一个Nacos服务器,使得客户端可以连接到该服务器。
ClientConfig
ClientConfig
用于配置客户端的行为和属性,包括命名空间ID、超时时间、日志级别、缓存目录等。ClientConfig
中的命名空间ID(NamespaceId
)指定了客户端要操作的特定命名空间。通过命名空间ID,客户端可以确保只管理属于该命名空间的配置和服务。
例如:
cc := *constant.NewClientConfig(constant.WithNamespaceId("ace1b5fe-80c3-4fab-b89a-625f9ff41093"), // 命名空间IDconstant.WithTimeoutMs(5000),constant.WithNotLoadCacheAtStart(true),constant.WithLogDir("/tmp/nacos/log"),constant.WithCacheDir("/tmp/nacos/cache"),constant.WithLogLevel("debug"),constant.WithUsername("nacos"),constant.WithPassword("nacos"),
)
这段代码配置了客户端的行为,特别是指定了要操作的命名空间ID。
- ServerConfig:用于配置Nacos服务器的信息,告诉客户端如何连接到Nacos服务器。
- ClientConfig:用于配置客户端的行为和属性,包括命名空间ID,告诉客户端要操作哪个命名空间中的配置和服务。
通过这两个配置,客户端可以正确地连接到Nacos服务器,并操作指定命名空间中的配置和服务。以下是代码中两者的使用关系:
client, err := clients.NewConfigClient(vo.NacosClientParam{ClientConfig: &cc, // 客户端配置,包括命名空间ID等ServerConfigs: sc, // 服务器配置切片,用于连接Nacos服务器},
)
这里就创建了一个客户端用于访问服务器特定的命名空间。
命名空间是什么?
AI答 + 我的理解:在Nacos中,命名空间(Namespace)是一种用于隔离配置和服务的机制。通过命名空间,可以将不同的配置和服务分隔开来,避免它们之间的冲突和干扰。命名空间在Nacos中通常用于多环境(如开发环境、测试环境、生产环境)的配置管理,或者用于不同的项目或团队之间的配置隔离。
比如我的代码里面,命名空间ID是 "ace1b5fe-80c3-4fab-b89a-625f9ff41093"
。这个ID是一个唯一的标识符,用于指定一个特定的命名空间。通过这个命名空间ID,客户端可以操作属于该命名空间的配置和服务。
添加配置
// 发布配置
_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data", // 配置的数据IDGroup: "test-group", // 配置的分组Content: "hello world!", // 配置的内容
})
if err != nil {fmt.Printf("PublishConfig err:%+v \n", err) // 如果发布配置失败,打印错误信息
}_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data-2", // 第二个配置的数据IDGroup: "test-group", // 第二个配置的分组Content: "hello world!", // 第二个配置的内容
})
if err != nil {fmt.Printf("PublishConfig err:%+v \n", err) // 如果发布配置失败,打印错误信息
此处实现的功能为发布配置,和nacos控制台的发布配置功能是一样的
注意要选择相应的命名空间。
监视配置
// 获取配置
content, err := client.GetConfig(vo.ConfigParam{DataId: "test-data", // 要获取的配置的数据IDGroup: "test-group", // 要获取的配置的分组
})
fmt.Println("GetConfig,config :" + content) // 打印获取到的配置内容// 监听配置变更
err = client.ListenConfig(vo.ConfigParam{DataId: "test-data", // 要监听的配置的数据IDGroup: "test-group", // 要监听的配置的分组OnChange: func(namespace, group, dataId, data string) {fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) // 配置变更时打印信息},
})
这里实现了获取配置,以及对配置的监听,为什么这里可以监听到之后配置的变更呢?这里我认为应该是在函数内部使用了goroutine来实现的,一旦检测到有变化,监听器就会发出响应。
修改/删除配置
_, err = client.PublishConfig(vo.ConfigParam{DataId: "test-data", // 要修改的配置的数据IDGroup: "test-group", // 要修改的配置的分组Content: "test-listen", // 修改后的配置内容
})
_, err = client.DeleteConfig(vo.ConfigParam{DataId: "test-data", // 要删除的配置的数据IDGroup: "test-group", // 要删除的配置的分组
})
if err != nil {fmt.Printf("DeleteConfig err:%+v \n", err) // 如果删除配置失败,打印错误信息
}
至于修改以及删除的逻辑就很简单了,这里不多赘述
nacos服务注册
先看代码示例,在接下来我会详细讲解每一步
package mainimport ("fmt""github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client""time""github.com/nacos-group/nacos-sdk-go/v2/clients""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/util""github.com/nacos-group/nacos-sdk-go/v2/vo"
)func main() {// 创建 ServerConfig,配置 Nacos 服务器地址、端口及上下文路径sc := []constant.ServerConfig{*constant.NewServerConfig("192.168.195.129", 8848, constant.WithContextPath("/nacos")),}// 创建 ClientConfig,配置客户端的基本参数,如命名空间、超时时间、日志路径等cc := *constant.NewClientConfig(constant.WithNamespaceId("ace1b5fe-80c3-4fab-b89a-625f9ff41093"),constant.WithTimeoutMs(5000),constant.WithNotLoadCacheAtStart(true),constant.WithLogDir("/tmp/nacos/log"),constant.WithCacheDir("/tmp/nacos/cache"),constant.WithLogLevel("debug"),constant.WithUsername("nacos"), // 用户名constant.WithPassword("nacos"), // 密码)// 创建命名服务客户端client, err := clients.NewNamingClient(vo.NacosClientParam{ClientConfig: &cc,ServerConfigs: sc,},)if err != nil {panic(err) // 如果客户端创建失败,则抛出异常}// 注册服务实例到 NacosregisterServiceInstance(client, vo.RegisterInstanceParam{Ip: "10.0.0.10", // 服务实例的 IP 地址Port: 8848, // 服务实例的端口号ServiceName: "test.go", // 服务名称GroupName: "group-a", // 分组名称ClusterName: "cluster-a", // 集群名称Weight: 10, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例Metadata: map[string]string{"idc": "shanghai"}, // 元数据信息})//从 Nacos 取消注册服务实例deRegisterServiceInstance(client, vo.DeregisterInstanceParam{Ip: "10.0.0.10", // 服务实例的 IP 地址Port: 8848, // 服务实例的端口号ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Cluster: "cluster-a", // 集群名称Ephemeral: true, // 必须为临时实例})time.Sleep(1 * time.Second) // 等待 1 秒// 批量注册多个服务实例batchRegisterServiceInstance(client, vo.BatchRegisterInstanceParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Instances: []vo.RegisterInstanceParam{{Ip: "10.0.0.10", // 第一个服务实例的 IP 地址Port: 8848, // 第一个服务实例的端口号Weight: 10, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例ClusterName: "cluster-a", // 集群名称Metadata: map[string]string{"idc": "shanghai"}, // 元数据信息}, {Ip: "10.0.0.12", // 第二个服务实例的 IP 地址Port: 8848, // 第二个服务实例的端口号Weight: 7, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例ClusterName: "cluster-a", // 集群名称Metadata: map[string]string{"idc": "shanghai"}, // 元数据信息}},})time.Sleep(1 * time.Second) // 等待 1 秒// 根据服务名称、分组名称和集群名称获取服务信息getService(client, vo.GetServiceParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Clusters: []string{"cluster-a"}, // 集群名称列表})// 获取指定服务的所有实例selectAllInstances(client, vo.SelectAllInstancesParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Clusters: []string{"cluster-a"}, // 集群名称列表})// 获取指定服务的健康实例selectInstances(client, vo.SelectInstancesParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Clusters: []string{"cluster-a"}, // 集群名称列表HealthyOnly: true, // 仅获取健康实例})// 根据加权随机算法获取一个健康实例selectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Clusters: []string{"cluster-a"}, // 集群名称列表})// 订阅服务变更,当服务信息发生变化时,会触发回调函数subscribeParam := &vo.SubscribeParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称SubscribeCallback: func(services []model.Instance, err error) {fmt.Printf("callback return services:%s \n\n", util.ToJsonString(services)) // 变更时打印服务实例信息},}subscribe(client, subscribeParam)// 等待 3 秒,让客户端从服务端拉取变更time.Sleep(3 * time.Second)// 更新服务实例信息updateServiceInstance(client, vo.UpdateInstanceParam{Ip: "10.0.0.11", // 更新后的 IP 地址Port: 8848, // 服务实例的端口号ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称ClusterName: "cluster-a", // 集群名称Weight: 10, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例Metadata: map[string]string{"idc": "beijing1"}, // 更新后的元数据信息})// 等待 3 秒,让客户端从服务端拉取变更time.Sleep(3 * time.Second)// 取消订阅服务变更unSubscribe(client, subscribeParam)// 获取指定分组下的所有服务名称列表getAllService(client, vo.GetAllServiceInfoParam{GroupName: "group-a", // 分组名称PageNo: 1, // 分页页码PageSize: 10, // 每页大小})
}//==========================================以下为函数实现===================================================// registerServiceInstance 向 Nacos 注册一个服务实例
func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {// 调用 RegisterInstance 方法注册服务实例success, err := client.RegisterInstance(param)if !success || err != nil {// 如果注册失败,抛出 panic 并打印错误信息panic("RegisterServiceInstance failed!" + err.Error())}// 打印注册参数和结果fmt.Printf("RegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}// batchRegisterServiceInstance 向 Nacos 批量注册多个服务实例
func batchRegisterServiceInstance(client naming_client.INamingClient, param vo.BatchRegisterInstanceParam) {// 调用 BatchRegisterInstance 方法批量注册服务实例success, err := client.BatchRegisterInstance(param)if !success || err != nil {// 如果批量注册失败,抛出 panic 并打印错误信息panic("BatchRegisterServiceInstance failed!" + err.Error())}// 打印批量注册参数和结果fmt.Printf("BatchRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}// deRegisterServiceInstance 从 Nacos 取消注册一个服务实例
func deRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {// 调用 DeregisterInstance 方法取消注册服务实例success, err := client.DeregisterInstance(param)if !success || err != nil {// 如果取消注册失败,抛出 panic 并打印错误信息panic("DeRegisterServiceInstance failed!" + err.Error())}// 打印取消注册参数和结果fmt.Printf("DeRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}// updateServiceInstance 更新 Nacos 中已注册的服务实例信息
func updateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) {// 调用 UpdateInstance 方法更新服务实例信息success, err := client.UpdateInstance(param)if !success || err != nil {// 如果更新失败,抛出 panic 并打印错误信息panic("UpdateInstance failed!" + err.Error())}// 打印更新参数和结果fmt.Printf("UpdateServiceInstance,param:%+v,result:%+v \n\n", param, success)
}// getService 从 Nacos 获取指定服务的信息
func getService(client naming_client.INamingClient, param vo.GetServiceParam) {// 调用 GetService 方法获取服务信息service, err := client.GetService(param)if err != nil {// 如果获取服务信息失败,抛出 panic 并打印错误信息panic("GetService failed!" + err.Error())}// 打印获取服务信息的参数和服务信息结果fmt.Printf("GetService,param:%+v, result:%+v \n\n", param, service)
}// selectAllInstances 从 Nacos 获取指定服务的所有实例
func selectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) {// 调用 SelectAllInstances 方法获取所有实例instances, err := client.SelectAllInstances(param)if err != nil {// 如果获取所有实例失败,抛出 panic 并打印错误信息panic("SelectAllInstances failed!" + err.Error())}// 打印获取所有实例的参数和实例信息结果fmt.Printf("SelectAllInstance,param:%+v, result:%+v \n\n", param, instances)
}// selectInstances 从 Nacos 获取指定服务的健康实例
func selectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) {// 调用 SelectInstances 方法获取健康实例instances, err := client.SelectInstances(param)if err != nil {// 如果获取健康实例失败,抛出 panic 并打印错误信息panic("SelectInstances failed!" + err.Error())}// 打印获取健康实例的参数和实例信息结果fmt.Printf("SelectInstances,param:%+v, result:%+v \n\n", param, instances)
}// selectOneHealthyInstance 从 Nacos 获取一个健康实例(使用加权随机算法)
func selectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {// 调用 SelectOneHealthyInstance 方法获取一个健康实例instances, err := client.SelectOneHealthyInstance(param)if err != nil {// 如果获取健康实例失败,抛出 panic 并打印错误信息panic("SelectOneHealthyInstance failed!")}// 打印获取健康实例的参数和实例信息结果fmt.Printf("SelectOneHealthyInstance,param:%+v, result:%+v \n\n", param, instances)
}// subscribe 订阅 Nacos 中指定服务的变化
func subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {// 调用 Subscribe 方法订阅服务变化client.Subscribe(param)
}// unSubscribe 取消订阅 Nacos 中指定服务的变化
func unSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {// 调用 Unsubscribe 方法取消订阅服务变化client.Unsubscribe(param)
}// getAllService 从 Nacos 获取指定分组下的所有服务名称列表
func getAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) {// 调用 GetAllServicesInfo 方法获取所有服务名称列表service, err := client.GetAllServicesInfo(param)if err != nil {// 如果获取服务名称列表失败,抛出 panic 并打印错误信息panic("GetAllService failed!")}// 打印获取服务名称列表的参数和服务名称列表结果fmt.Printf("GetAllService,param:%+v, result:%+v \n\n", param, service)
}
服务的注册
registerServiceInstance(client, vo.RegisterInstanceParam{Ip: "10.0.0.10", // 服务实例的 IP 地址Port: 8848, // 服务实例的端口号ServiceName: "test.go", // 服务名称GroupName: "group-a", // 分组名称ClusterName: "cluster-a", // 集群名称Weight: 10, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例Metadata: map[string]string{"idc": "shanghai"}, // 元数据信息
})
这里通过调用函数实现服务的注册,其中test.go只是是服务的名称,在注册服务之后,可以通过通过服务实例的ip地址和端口号进行访问,随后访问这些地址上运行的实际程序。
而这个函数是我们自己实现的,我们可以来看看函数的内部:
func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {// 调用 RegisterInstance 方法注册服务实例success, err := client.RegisterInstance(param)if !success || err != nil {// 如果注册失败,抛出 panic 并打印错误信息panic("RegisterServiceInstance failed!" + err.Error())}// 打印注册参数和结果fmt.Printf("RegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
这里直接通过调用client的方法来为我们注册服务,而这个client
可以和nacos服务器进行通信,可以注册、取消注册、更新服务实例的信息,以及从 Nacos 服务器获取这些信息。
取消服务的注册
deRegisterServiceInstance(client, vo.DeregisterInstanceParam{Ip: "10.0.0.10", // 服务实例的 IP 地址Port: 8848, // 服务实例的端口号ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Cluster: "cluster-a", // 集群名称Ephemeral: true, // 必须为临时实例
})
取消注册服务,以上均为必须要传递的参数,用于匹配将要取消注册的服务实例
实现函数:
func deRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {// 调用 DeregisterInstance 方法取消注册服务实例success, err := client.DeregisterInstance(param)if !success || err != nil {// 如果取消注册失败,抛出 panic 并打印错误信息panic("DeRegisterServiceInstance failed!" + err.Error())}// 打印取消注册参数和结果fmt.Printf("DeRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
和注册的方式类似,直接通过调用cilent的方法,并传递需要取消注册的服务实例的必要参数,用于定位。
批量注册
batchRegisterServiceInstance(client, vo.BatchRegisterInstanceParam{ServiceName: "demo.go", // 服务名称GroupName: "group-a", // 分组名称Instances: []vo.RegisterInstanceParam{{Ip: "10.0.0.10", // 第一个服务实例的 IP 地址Port: 8848, // 第一个服务实例的端口号Weight: 10, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例ClusterName: "cluster-a", // 集群名称Metadata: map[string]string{"idc": "shanghai"}, // 元数据信息}, {Ip: "10.0.0.12", // 第二个服务实例的 IP 地址Port: 8848, // 第二个服务实例的端口号Weight: 7, // 权重Enable: true, // 是否启用Healthy: true, // 是否健康Ephemeral: true, // 是否为临时实例ClusterName: "cluster-a", // 集群名称Metadata: map[string]string{"idc": "shanghai"}, // 元数据信息}},
})
和名字一样,可以想函数中传递多个参数,用于注册服务,但不同的一点是,服务的名称和分组名称独立了出来,这表示注册的服务均属于同一种服务和分组,而此时传递的结构体中包含了多个instance实例(这个参数就是服务单独注册时使用到的结构体的切片)。
函数实现
func batchRegisterServiceInstance(client naming_client.INamingClient, param vo.BatchRegisterInstanceParam) {// 调用 BatchRegisterInstance 方法批量注册服务实例success, err := client.BatchRegisterInstance(param)if !success || err != nil {// 如果批量注册失败,抛出 panic 并打印错误信息panic("BatchRegisterServiceInstance failed!" + err.Error())}// 打印批量注册参数和结果fmt.Printf("BatchRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
无需多说,也是通过调用方法来实现服务注册。
http实例自动注册服务
先看看代码的实现,然后我会一步一步细说:
package mainimport ("context""fmt""github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client""net/http""os""os/signal""syscall""time""github.com/nacos-group/nacos-sdk-go/v2/clients""github.com/nacos-group/nacos-sdk-go/v2/common/constant""github.com/nacos-group/nacos-sdk-go/v2/vo"
)func main() {// 1. 创建 Nacos 客户端client := createNacosClient()// 2. 定义服务实例的元数据信息serviceName := "servicetest" // 服务名称groupName := "group1" // 分组名称clusterName := "cluster-a" // 集群名称ip := "127.0.0.1" // 服务实例的 IP 地址(当前虚拟机的 IP 地址)port := 8080 // 服务实例的端口号metadata := map[string]string{ // 元数据信息"idc": "shanghai",}// 3. 注册服务实例到 NacosregisterServiceInstance(client, vo.RegisterInstanceParam{Ip: ip,Port: uint64(port),ServiceName: serviceName,GroupName: groupName,ClusterName: clusterName,Weight: 10,Enable: true,Healthy: true,Ephemeral: true,Metadata: metadata,})// 4. 启动 HTTP 服务http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, this is demo.go service at %s:%d!", ip, port)})server := &http.Server{Addr: fmt.Sprintf("%s:%d", ip, port),Handler: nil,}go func() {fmt.Printf("Starting HTTP server at http://%s:%d\n", ip, port)if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {fmt.Printf("HTTP server failed: %v\n", err)}}()// 5. 监听系统信号,实现优雅关闭quit := make(chan os.Signal, 1)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<-quitfmt.Println("Shutting down server...")// 6. 取消注册服务实例deRegisterServiceInstance(client, vo.DeregisterInstanceParam{Ip: ip,Port: uint64(port),ServiceName: serviceName,GroupName: groupName,Cluster: clusterName,Ephemeral: true,})// 7. 关闭 HTTP 服务ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()if err := server.Shutdown(ctx); err != nil {fmt.Printf("HTTP server shutdown failed: %v\n", err)}fmt.Println("Server exited gracefully")
}// createNacosClient 创建 Nacos 客户端
func createNacosClient() naming_client.INamingClient {// 创建 ServerConfigsc := []constant.ServerConfig{*constant.NewServerConfig("192.168.195.129", // Nacos 服务器的 IP 地址8848, // Nacos 服务器的端口号constant.WithContextPath("/nacos"), // Nacos 服务器的上下文路径),}// 创建 ClientConfigcc := *constant.NewClientConfig(constant.WithNamespaceId(""), // 命名空间 IDconstant.WithTimeoutMs(5000), // 超时时间constant.WithNotLoadCacheAtStart(true), // 启动时不加载缓存constant.WithLogDir("/tmp/nacos/log"), // 日志目录constant.WithCacheDir("/tmp/nacos/cache"), // 缓存目录constant.WithLogLevel("debug"), // 日志级别constant.WithUsername("nacos"),constant.WithPassword("nacos"),)// 创建命名服务客户端client, err := clients.NewNamingClient(vo.NacosClientParam{ClientConfig: &cc,ServerConfigs: sc,},)if err != nil {panic("Failed to create Nacos client: " + err.Error())}return client
}// registerServiceInstance 向 Nacos 注册一个服务实例
func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {success, err := client.RegisterInstance(param)if !success || err != nil {panic("Failed to register service instance: " + err.Error())}fmt.Printf("Registered service instance: %+v\n", param)
}wd// deRegisterServiceInstance 从 Nacos 取消注册一个服务实例
func deRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {success, err := client.DeregisterInstance(param)if !success || err != nil {panic("Failed to deregister service instance: " + err.Error())}fmt.Printf("Deregistered service instance: %+v\n", param)
}
创建client
第一步便是我们的创建client,此时我们也需要serverconfig和clientconfig
但是注册的client类型却不一样,注意,我们之前crud的时候采取的并不是naming client而是configclient,此处需要注意以下
func createNacosClient() naming_client.INamingClient {// 创建 ServerConfigsc := []constant.ServerConfig{*constant.NewServerConfig("192.168.195.129", // Nacos 服务器的 IP 地址8848, // Nacos 服务器的端口号constant.WithContextPath("/nacos"), // Nacos 服务器的上下文路径),}// 创建 ClientConfigcc := *constant.NewClientConfig(constant.WithNamespaceId(""), // 命名空间 IDconstant.WithTimeoutMs(5000), // 超时时间constant.WithNotLoadCacheAtStart(true), // 启动时不加载缓存constant.WithLogDir("/tmp/nacos/log"), // 日志目录constant.WithCacheDir("/tmp/nacos/cache"), // 缓存目录constant.WithLogLevel("debug"), // 日志级别constant.WithUsername("nacos"),constant.WithPassword("nacos"),)// 创建命名服务客户端client, err := clients.NewNamingClient(vo.NacosClientParam{ClientConfig: &cc,ServerConfigs: sc,},)if err != nil {panic("Failed to create Nacos client: " + err.Error())}return client
}
其他都是一样的,需要指定注册在哪一个服务器,哪一个命名空间。
注册服务到nacos服务器
serviceName := "servicetest" // 服务名称
groupName := "group1" // 分组名称
clusterName := "cluster-a" // 集群名称
ip := "127.0.0.1" // 服务实例的 IP 地址(当前虚拟机的 IP 地址)
port := 8080 // 服务实例的端口号
metadata := map[string]string{ // 元数据信息"idc": "shanghai",
}// 3. 注册服务实例到 Nacos
registerServiceInstance(client, vo.RegisterInstanceParam{Ip: ip,Port: uint64(port),ServiceName: serviceName,GroupName: groupName,ClusterName: clusterName,Weight: 10,Enable: true,Healthy: true,Ephemeral: true,Metadata: metadata,
})
此处我们需要指定当前服务实例所在的ip,端口,以及服务名称等一系列参数,这里只是想nacos服务器表示了这个服务时存在
的,随后我们再启动我们的http服务。
启动http服务
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "Hello, this is demo.go service at %s:%d!", ip, port)
})server := &http.Server{Addr: fmt.Sprintf("%s:%d", ip, port),Handler: nil,
}go func() {fmt.Printf("Starting HTTP server at http://%s:%d\n", ip, port)if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {fmt.Printf("HTTP server failed: %v\n", err)}
}()
这里无需多说,就是随便启动了一个http服务
优雅结束
// 5. 监听系统信号,实现优雅关闭
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quitfmt.Println("Shutting down server...")// 6. 取消注册服务实例
deRegisterServiceInstance(client, vo.DeregisterInstanceParam{Ip: ip,Port: uint64(port),ServiceName: serviceName,GroupName: groupName,Cluster: clusterName,Ephemeral: true,
})// 7. 关闭 HTTP 服务
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {fmt.Printf("HTTP server shutdown failed: %v\n", err)
}fmt.Println("Server exited gracefully")
最后优雅的结束。
结语
关于这篇文章,主要写出来也是想逼自己去看看官方的示例,以便于自己更能理解nacos是怎么运作的,在此之前我网上查了很多资料,也问了AI,但都没学到什么东西说实话,毕竟Golang目前的学习环境跟java比起来真的差远了,反而今晚上看了一会官方给的示例让我收获很大…
所以真的得去看官方的文档。
以上就是我今天所学到的内容,希望对你也会有帮助,如果有问题,欢迎给我留言
毕竟我也只是个初学者,如果有错误希望包涵以下
相关文章:
【Golang/nacos】nacos配置的增删查改,以及服务注册的golang实例及分析
前言 本文分析的实例来源于nacos在github上的开源仓库 nacos配置的增删查改 先具体来看一段代码,我将逐步分析每一段的作用 package mainimport ("fmt""time""github.com/nacos-group/nacos-sdk-go/clients""github.com/naco…...
[手机Linux] 七,NextCloud优化设置
安装完成后在个人设置里发现很多警告,一一消除。 只能一条一条解决了。 关于您的设置有一些错误。 1,PHP 内存限制低于建议值 512 MB。 设置php配置文件: /usr/local/php/etc/php.ini 把里面的: memory_limit 128M 根据你自…...
浅谈云计算15 | 存储可靠性技术(RAID)
存储可靠性技术 一、存储可靠性需求1.1 数据完整性1.2 数据可用性1.3 故障容错性 二、传统RAID技术剖析2.1 RAID 02.2 RAID 12.3 RAID 52.4 RAID 62.5 RAID 10 三、RAID 2.0技术3.1 RAID 2.0技术原理3.1.1 两层虚拟化管理模式3.1.2 数据分布与重构 3.2 RAID 2.0技术优势3.2.1 自…...
vscode【实用插件】Material Icon Theme 美化文件图标
安装 在 vscode 插件市场的搜索 Material Icon Theme点 安装 效果...
json().get() 和 json[““] 的区别
以下是 json().get() 和 json[“”] 的区别: 使用方法和语法 json[“”]: 这是使用字典的索引操作符 [] 来访问 JSON 数据。假设 json 是一个字典,你可以通过 json[“key”] 的方式来获取对应 key 的值。 示例: python import js…...
商用车电子电气零部件电磁兼容条件和试验—目录
写在前面 本系列文章主要讲解商用车电子/电气零部件或系统的传导抗干扰、传导发射和辐射抗干扰、电场辐射发射以及静电放电等试验内容及要求,高压试验项目内容及要求。 若有相关问题,欢迎评论沟通,共同进步。(*^▽^*) 目录 商用车电子电气零部件电磁兼容条件和试验(1)—…...
【新人系列】Python 入门(二十六):常见设计模式
✍ 个人博客:https://blog.csdn.net/Newin2020?typeblog 📝 专栏地址:https://blog.csdn.net/newin2020/category_12801353.html 📣 专栏定位:为 0 基础刚入门 Python 的小伙伴提供详细的讲解,也欢迎大佬们…...
【跟着官网学技术系列之MySQL】第7天之创建和使用数据库1
前言 在当今信息爆炸的时代,拥有信息检索的能力很重要。 作为一名软件工程师,遇到问题,你会怎么办?带着问题去搜索引擎寻找答案?亦或是去技术官网,技术社区去寻找? 根据个人经验,一…...
Spark任务提交流程
当包含在application master中的spark-driver启动后,会与资源调度平台交互获取其他执行器资源,并通过反向注册通知对应的node节点启动执行容器。此外,还会根据程序的执行规划生成两个非常重要的东西,一个是根据spark任务执行计划生…...
使用python+pytest+requests完成自动化接口测试(包括html报告的生成和日志记录以及层级的封装(包括调用Json文件))
一、API的选择 我们进行接口测试需要API文档和系统,我们选择JSONPlaceholder免费API,因为它是一个非常适合进行接口测试、API 测试和学习的工具。它免费、易于使用、无需认证,能够快速帮助开发者模拟常见的接口操作(增、删、改、…...
Docker的入门
一、安装Docker 本教程参考官网文档,链接如下: CentOS | Docker Docs 这个教程是基于你的虚拟机已经弄好了(虚拟机用的CentOS),并且有SecureCRT或者MobaXterm等等任意一个工具 1.1 卸载旧版 如果系统中存在旧版本的Docker&a…...
机器学习:监督学习与非监督学习
监督学习是利用带有标签的数据进行训练,模型通过学习输入和输出之间的关系来进行预测。也就是说,数据集中既有输入特征,也有对应的输出标签,模型的目标是找到从输入到输出的映射关系。 而无监督学习则使用没有标签的数据进行训练,模型的任务是发现数据中的内在结构或模式…...
神经网络常见操作(卷积)输入输出
卷积 dimd的tensor可以进行torch.nn.Convnd(in_channels,out_channels),其中nd-1,d-2对于torch.nn.Convnd(in_channels,out_channels),改变的是tensor的倒数n1维的大小 全连接 使用torch.nn.Linear(in_features,out_features,bias)实现YXWT b,其中X 的形状为 (ba…...
海云安开发者安全智能助手D10荣膺 “ AI标杆产品 ” 称号,首席科学家齐大伟博士入选2024年度 “ 十大杰出青年 ”
2024年12月27日,粤港澳大湾区AI领袖峰会在深圳成功举办,大会表彰了在人工智能技术创新、应用实践和产业发展等方面取得优异成绩的企业和个人,深圳海云安网络安全技术有限公司开发者安全智能助手D10荣膺“AI标杆产品”称号。同时,公…...
O2O同城系统架构与功能分析
2015工作至今,10年资深全栈工程师,CTO,擅长带团队、攻克各种技术难题、研发各类软件产品,我的代码态度:代码虐我千百遍,我待代码如初恋,我的工作态度:极致,责任ÿ…...
C#,入门教程(27)——应用程序(Application)的基础知识
上一篇: C#,入门教程(26)——数据的基本概念与使用方法https://blog.csdn.net/beijinghorn/article/details/124952589 一、什么是应用程序 Application? 应用程序是编程的结果。一般把代码经过编译(等)过程&#…...
计算机网络(四)——网络层
目录 一、功能 二、IP数据报分片 三、DHCP动态主机配置协议 四、网络地址转换(NAT)技术 五、无分类编址CIDR 六、ARP地址解析协议 七、ICMP网际控制报文协议 八、IPv4和IPv6的区别 九、IPv4向IPv6的两种过渡技术——双栈协议和隧道技术 十、路由…...
VSCode的配置与使用(C/C++)
从0开始教你在vscode调试一个C文件 一.首先是配置你的编译环境,添加到环境变量(默认你是全新的电脑,没有安装vs2019之类的) 原因:因为相比于vs2019,vscode只是个代码编辑器,相当于一个彩色的、…...
《机器学习》——TF-IDF(关键词提取)
文章目录 TF-IDF简介TF-IDF应用场景TF-IDF模型模型参数主要参数 TF-IDF实例实例步骤导入数据和模块处理数据处理文章开头和分卷处理将各卷内容存储到数据帧jieba分词和去停用词处理 计算 TF-IDF 并找出核心关键词 TF-IDF简介 TF - IDF(Term Frequency - Inverse Do…...
金仓Kingbase客户端KStudio报OOM:Java heap space socketTimeout
找到Kingbase\ES\V8\KESRealPro\V008R006C006B0021\ClientTools\guitools\KStudio\KStudio.ini 修改JVM参数: 默认值: -Xms512m -Xmx1024m 改为: -Xms1024m -Xmx2048m -XX:MaxPermSize512m SQL查询报错:An I/O error occurred …...
XML在线格式化 - 加菲工具
XML在线格式化 打开网站 加菲工具 选择“XML 在线格式化” 输入XML,点击左上角的“格式化”按钮 得到格式化后的结果...
thinkphp8.0 likeadmin 框架添加API 文档自动生成工具 apidoc支持
Apidoc 是一个便捷的 API 文档自动生成工具,它能帮助开发者快速生成和管理 API 文档。以下是 Apidoc 的主要特点和功能: 主要特点 开箱即用 安装后,无需繁杂配置,直接按照文档编写注释,即可自动生成 API 文档。 轻松编…...
计算机网络 (44)电子邮件
一、概述 电子邮件(Electronic Mail,简称E-mail)是因特网上最早流行的应用之一,并且至今仍然是因特网上最重要、最实用的应用之一。它利用计算机技术和互联网,实现了信息的快速、便捷传递。与传统的邮政系统相比&#…...
【Idea启动项目报错NegativeArraySizeException】
项目场景: Idea启动项目报错(打包不报错),项目在服务器部署运行没有问题,尝试了重启idea、重启电脑、maven clean/install 都不行 maven-resources-production:sample: java.lang.NegativeArraySizeException: -5833…...
长安“战疫”网络安全公益赛的一些随想
起因 今年刚进入大学,开始带校队,为了培养校队新成员,也就一直计划着和当地的一些高校合作交流,但是由于种种原因一直被搁置下来。正巧学校信息中心和四叶草有一个培训项目的合作,学校的网安协会也算是沾了光成为了培…...
【网络编程】基础知识
目录 网络发展史 局域网和广域网 局域网(LAN) 广域网(Wan) 光猫 路由器 网线 设备通信的要素 IP地址 基本概念 地址划分 特殊地址(后续编程使用) IP地址转换 字节序 网络模型 网络的体系结…...
RK3568平台(音频篇)lineout无声调试
一.声音硬件框架 硬件HP_MUTE已强制拉低。 二.设备树配置 es8388_sound: es8388-sound {status = "okay";compatible = "rockchip,multicodecs-card";rockchip,card-name = "rockchip-es8388";hp-det-gpio = <&gpio1 RK_PD2 GPIO_ACT…...
计算机组成原理(计算机系统3)--实验三:取指和指令译码设计
一、 实验目标: 设计完成一个连续取指令并进行指令译码的电路,从而掌握设计简单数据通路的基本方法。 二、实验内容 本实验完成:1)首先完成一个译码器;2)接着实现一个寄存器文件;3࿰…...
紫光无人机AI飞控平台介绍
随着无人机技术的迅猛发展,无人机飞控平台的智能化需求不断提升。紫光无人机AI飞控平台作为一款创新型产品,为用户提供了从飞行控制到任务管理的一站式解决方案,尤其在AI实时识别和事件分析方面具有显著优势。本文将介绍平台的核心功能、技术…...
基于EMQX+MQTT+ESP32+Openharmony的开发实例
EMQX介绍 EMQ X 是基于 Erlang/OTP 平台开发的 MQTT 消息服务器,是开源社区中最流行的 MQTT 消息服务器。EMQX 是开源百万级分布式 MQTT 消息服务器(MQTT Messaging Broker),用于支持各种接入标准 MQTT 协议的设备,实…...
npm发布组件(vue3+webpack)
1.初始化Vue项目 vue create my-app 2.本地运行 npm run serve 3.新增目录和文件 1. src/package/index.js 2. src/package/wlz-btn/index.vue 3. src/package/wlz-input/index.vue // src\package\index.js import WlzBtn from "./wlz-btn"; import WlzInput …...
kubuntu24.04配置vmware17.5.1
背景 个人主机的最后一次折腾吧。 丝滑上网前提:singbox实践https://blog.csdn.net/qq_43652666/article/details/145190110 vmware 博通官网下载vmware workstation pro 17.5.1版本,注意一个新注册的账号只能下载一个win版本的vmware和一个linux版本…...
开发规范
开发规范 企业项目开发有2种开发模式:前后台混合开发和前后台分离开发。 前后台混合开发 顾名思义就是前台后台代码混在一起开发,如下图所示: 这种开发模式有如下缺点: 沟通成本高:后台人员发现前端有问题…...
大模型UI:Gradio全解11——Chatbot:融合大模型的聊天机器人(4)
大模型UI:Gradio全解11——Chatbot:融合大模型的聊天机器人(4) 前言本篇摘要11. Chatbot:融合大模型的多模态聊天机器人11.4 使用Blocks创建自定义聊天机器人11.4.1 简单聊天机器人演示11.4.2 流式传输Chatbot11.4.3 添…...
[操作系统] 深入理解操作系统的概念及定位
概念 任何计算机系统都包含⼀个基本的程序集合,称为操作系统(OS)。 其核心功能如图片所示,包括: 内核 (Kernel): 内核是操作系统的核心部分,被认为是狭义上的操作系统,直接与硬件打交道。负责进程管理、内…...
redhat安装docker 24.0.7
1、下载docker镜像包 wget https://download.docker.com/linux/static/stable/x86_64/docker-24.0.7.tgz 2、解压 tar -xvf docker-24.0.7.tgz 3、解压的docker文件夹全部移动至/usr/bin目录 cd docker cp -p docker/* /usr/bin 4、注册服务 vi /usr/lib/systemd/syste…...
数据库基础实验1(创建表,设置外键,检查,不为空,主键等约束)安装mysql详细步骤
安装MySQL详细步骤 1. 下载 MySQL 安装程序 访问 MySQL 官方网站:MySQL Downloads。在下载页面,选择 "MySQL Community (GPL) Downloads"。在 "MySQL Community Server" 部分,根据你的操作系统(Windows&…...
如何攻击一个服务器(仅用于教育及娱乐实验目的)
import socket import osdef create_virus():# 创建一个简单的病毒脚本,它会不断尝试连接目标服务器并发送恶意数据virus_code """ import socket import time import threadingdef attack_server(ip, port):while True:try:s socket.socket(socke…...
HarmonyOS NEXT应用开发边学边玩系列:从零实现一影视APP (二、首页轮播图懒加载的实现)
在开发一款影视APP时,首页的轮播图是一个非常重要的部分。它不仅能够吸引用户的注意力,还能有效地推广重点内容。为了提升应用的性能和用户体验,可以实现轮播图的懒加载功能。本文将详细介绍如何在HarmonyOS NEXT应用开发中实现这一功能。 1.…...
Jmeter 简单使用、生成测试报告(一)
一、下载Jmter 去官网下载,我下载的是apache-jmeter-5.6.3.zip,解压后就能用。 二、安装java环境 JMeter是基于Java开发的,运行JMeter需要Java环境。 1.下载JDK、安装Jdk 2.配置java环境变量 3.验证安装是否成功(java -versio…...
采用海豚调度器+Doris开发数仓保姆级教程(满满是踩坑干货细节,持续更新)
目录 一、采用海豚调度器+Doris开发平替CDH Hdfs + Yarn + Hive + Oozie的理由。 1. 架构复杂性 2. 数据处理性能 3. 数据同步与更新 4. 资源利用率与成本 6. 生态系统与兼容性 7. 符合信创或国产化要求 二、ODS层接入数据 接入kafka实时数据 踩坑的问题细节 三、海…...
大疆最新款无人机发布,可照亮百米之外目标
近日,DJI 大疆发布全新小型智能多光旗舰 DJI Matrice 4 系列,包含 Matrice 4T 和 Matrice 4E 两款机型。DJI Matrice 4E 价格为27888 元起,DJI Matrice 4T价格为38888元起。 图片来源:大疆官网 DJI Matrice 4E DJI Matrice 4T D…...
无公网IP 实现外网访问本地 Docker 部署 Navidrome
Navidrome 是一款可以在 macOS、Linux、Windows以及 Docker 等平台上运行的跨平台开源音乐服务器应用,它支持传输常见的 MP3、FLAC、WAV等音频格式。允许用户通过 Web 界面或 API 进行音乐库的管理和访问。本文就介绍如何快速在 Linux 系统使用 Docker 进行本地部署…...
踏上 C++ 编程之旅:开篇之作
踏上 C 编程之旅:开篇之作 在计算机编程的广袤天地中,C 宛如一座巍峨的高峰,吸引着无数开发者攀登探索。今天,就让我们一同开启这段充满挑战与惊喜的 C 编程之旅,在代码的世界里开辟属于自己的道路。 一、为什么选择…...
JS逆向系列之某考古站数据解密
声明 本文章中所有内容仅供学习交流,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请私信我立即删除! 文章目录 声明本次目标网址逆向分析ing代码python实现最近太忙了,博客摆烂了好久,狗头保命.jpg。 本次目标网址 aHR0cHM6Ly93d3cua2F…...
idea 如何安装 github copilot
idea 如何安装 github copilot 要在 IntelliJ IDEA 中安装 GitHub Copilot,可以按照以下步骤操作: 打开 IntelliJ IDEA: 启动 IntelliJ IDEA。 打开插件管理器: 点击菜单栏中的 File。 选择 Settings(Windows/Linux)或 Prefere…...
html5各行各业官网模板源码下载 (4)
文章目录 1.来源2.源码模板2.1 html实现酷炫美观的可视化大屏(十种风格示例,附源码)2.2 HTML5实现古典音乐网站源码模板22.3 HTML5实现古典音乐网站源码模板32.4 HTML5实现小鸟过管道小游戏源码2.5 HTML5实现俄罗斯方块小游戏2.5 HTML5实现剪刀石头布小游戏(附源码)…...
2023-2024 学年 广东省职业院校技能大赛(高职组)“信息安全管理与评估”赛题一
2023-2024 学年 广东省职业院校技能大赛(高职组“信息安全管理与评估”赛题一) 模块一:网络平台搭建与设备安全防护第一阶段任务书任务 1:网络平台搭建任务 2:网络安全设备配置与防护DCRS:DCFW:DCWS:DCBC:WAF: 模块二:网络安全事件…...
理解CPU负载与使用率
目录 CPU使用率 CPU负载 CPU使用率 定义:就像看一个工人干活的时间占他上班时间的比例。比如工人上班8小时,实际干活6小时,干活时间占比就是68100%75%。对于CPU,单核的看它被占用的时间占总时间的比例,多核的就把每个…...
鸿蒙-点击Notification通知并打开App的具体页面
意图通知 获取router事件中传递参数并跳转 目前点击通知消息打开应用的指定页面,通过为通知添加行为意图的方式。也就是在wants的parameters中设置自定义参数,然后在UIAbility的onNewWant或者onCreate方法中 解析配置的自定义参数信息判断跳转不同页面&a…...