使用wire重构商品微服务

一.wire简介

Wire 是一个轻巧的Golang依赖注入工具。它由Go Cloud团队开发,通过自动生成代码的方式在编译期完成依赖注入。

依赖注入是保持软件 “低耦合、易维护” 的重要设计准则之一。

此准则被广泛应用在各种开发平台之中,有很多与之相关的优秀工具。

其中最著名的当属 Spring,Spring IOC 作为框架的核心功能对Spring的发展到今天统治地位起了决定性作用。

依赖注入很重要,所以Golang社区中早已有人开发了相关工具, 比如来自Uber 的 dig 、来自Facebook 的 inject 。他们都通过反射机制实现了运行时依赖注入。

二.快速使用

2.1安装

安装很简单,运行 go get github.com/google/wire/cmd/wire 之后, wire 命令行工具 将被安装到 $GOPATH/bin 。只要确保 $GOPATH/bin 在 $PATH 中, wire 命令就可以在任何目录调用了。安装成功后运行如下命令
在这里插入图片描述

2.2快速入门

设计一个程序,其中 Event依赖Greeter,Greeter依赖Message

package mainimport ("fmt""github.com/pkg/errors""time"
)type Message stringfunc NewMessage(phrase string) Message {return Message(phrase)
}type Greeter struct {Message Message
}func NewGreeter(m Message) Greeter {return Greeter{Message: m}
}func (g Greeter) Greet() Message {return g.Message
}type Event struct {Greeter Greeter // <- adding a Greeter field
}func NewEvent(g Greeter) (Event, error) {if time.Now().Unix()%2 == 0 {return Event{}, errors.New("could not create event: event greeter is grumpy")}return Event{Greeter: g}, nil
}func (e Event) Start() {msg := e.Greeter.Greet()fmt.Println(msg)
}

如果运行Event需要逐个构建依赖,代码如下

func main() {message := NewMessage("lisus2000")greeter := NewGreeter(message)event := NewEvent(greeter)event.Start()
}

在此之前先介绍两个概念

Provider
Provider 你可以把它理解成工厂函数,这个函数的入参是依赖的属性,返回值为新一个新的类型实例

如下所示都是 provider 函数,在实际使用的时候,往往是一些简单的工厂函数,这个函数不会太复杂。

func NewMessage() Message {return Message("Hi there!")
}func NewGreeter(m Message) Greeter {return Greeter{Message: m}
}

Injector

我们常常在 wire.go 文件中定义 injector ,injector也是一个普通函数,它用来声明组件之间的依赖关系

如下代码,我们把Event、Greeter、Message 的工厂函数(provider)一股脑塞入wire.Build()中,代表着构建 Event依赖Greeter、Message。我们不必关心Greeter、Message之间的依赖关系,wire会帮我们处理

func InitializeEvent() Event {wire.Build(NewEvent, NewGreeter, NewMessage)return Event{}
}

编写wire.go文件

//go:build wireinject
// +build wireinjectpackage mainimport "github.com/google/wire"var wireSet = wire.NewSet(wire.Struct(new(Greeter), "Message"), NewMessage)func InitializeEvent(phrase string) (Event, error) {//我们常常在 wire.go 文件中定义 injector ,injector也是一个普通函数,它用来声明组件之间的依赖关系//如下代码,我们把Event、Greeter、Message 的工厂函数(provider)一股脑塞入wire.Build()中,//代表着构建 Event依赖Greeter、Message。我们不必关心Greeter、Message之间的依赖关系,wire会帮我们处理panic(wire.Build(NewEvent, wireSet))//return Event{}, nil
}

注:使用wire生成代码时,要在代码上加以下

可以在wire.go第一行加入 //+build wireinject (与//go:build wireinject等效)注释,确保了这个文件在我们正常编译的时候不会被引用

在带有wire.go目录下运行wire命令,就会生成wire_gen.go文件,如下图所示

在这里插入图片描述

在这里插入图片描述

完整的main.go文件如下

package mainimport ("fmt""github.com/pkg/errors""time"
)type Message stringfunc NewMessage(phrase string) Message {return Message(phrase)
}type Greeter struct {Message Message
}func NewGreeter(m Message) Greeter {return Greeter{Message: m}
}func (g Greeter) Greet() Message {return g.Message
}type Event struct {Greeter Greeter // <- adding a Greeter field
}func NewEvent(g Greeter) (Event, error) {if time.Now().Unix()%2 == 0 {return Event{}, errors.New("could not create event: event greeter is grumpy")}return Event{Greeter: g}, nil
}func (e Event) Start() {msg := e.Greeter.Greet()fmt.Println(msg)
}func main() {event, _ := InitializeEvent("hello")event.Start()
}

wire的进阶,详见https://blog.csdn.net/weixin_50071922/article/details/133278161

三.基于wire构建商品微服务

3.1编写商品微服务提供者
func NewGoodsAppWire(logOpts *log.Options, registrar registry.Registrar, serverOpts *options.ServerOptions,rpcServer *rpcserver.Server) (*gapp.App, error) {//初始化loglog.Init(logOpts)defer log.Flush()return gapp.New(gapp.WithName(serverOpts.Name),gapp.WithRPCServer(rpcServer),gapp.WithRegistrar(registrar),), nil
}
func NewRegistrar(registry *options.RegistryOptions) registry.Registrar {c := api.DefaultConfig()c.Address = registry.Addressc.Scheme = registry.Schemeclient, err := api.NewClient(c)if err != nil {panic(err)}return consul.New(client, consul.WithHealthCheck(true))
}
func NewGoodsRPCServerWire(telemetry *options.TelemetryOptions,serverOpts *options.ServerOptions, gserver gpb.GoodsServer) (*rpcserver.Server, error) {// 初始化 open-telemetry 的 exportertrace.InitAgent(trace.Options{Name:     telemetry.Name,Endpoint: telemetry.Endpoint,Sampler:  telemetry.Sampler,Batcher:  telemetry.Batcher,})// 这里会根据 endpoint 为单元注册 trace 服务的实例rpcAddr := fmt.Sprintf("%s:%d", serverOpts.Host, serverOpts.Port)var opts []rpcserver.ServerOptionopts = append(opts, rpcserver.WithAddress(rpcAddr))if serverOpts.EnableLimit {opts = append(opts, rpcserver.WithUnaryInterceptor(grpc.NewUnaryServerInterceptor()))}grpcServer := rpcserver.NewServer(opts...)gpb.RegisterGoodsServer(grpcServer.Server, gserver)return grpcServer, nil
}
func NewGoodsServerWire(srv v1.ServiceFactory) proto.GoodsServer {return &goodsServer{srv: srv,}
}
func NewGoodsServiceWire(data v1.DataFactory, dataSearch v12.SearchFactory) ServiceFactory {return &service{data:       data,dataSearch: dataSearch,}
}
func GetDBFactoryOr(mysqlOpts *options.MySQLOptions) (v1.DataFactory, error) {if mysqlOpts == nil && dbFactory == nil {return nil, errors.WithCode(code.ErrConnectDB, "failed to get mysql store factory")}var err erroronce.Do(func() {dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",mysqlOpts.Username,mysqlOpts.Password,mysqlOpts.Host,mysqlOpts.Port,mysqlOpts.Database)//希望大家自己可以去封装loggernewLogger := logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)logger.Config{SlowThreshold:             time.Second,                         // 慢 SQL 阈值LogLevel:                  logger.LogLevel(mysqlOpts.LogLevel), // 日志级别IgnoreRecordNotFoundError: true,                                // 忽略ErrRecordNotFound(记录未找到)错误Colorful:                  false,                               // 禁用彩色打印},)db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: newLogger,})if err != nil {return}sqlDB, _ := db.DB()dbFactory = &mysqlFactory{db: db,}//允许连接多少个mysqlsqlDB.SetMaxOpenConns(mysqlOpts.MaxOpenConnections)//允许最大的空闲的连接数sqlDB.SetMaxIdleConns(mysqlOpts.MaxIdleConnections)//重用连接的最大时长sqlDB.SetConnMaxLifetime(mysqlOpts.MaxConnectionLifetime)})if dbFactory == nil || err != nil {return nil, errors.WithCode(code.ErrConnectDB, "failed to get mysql store factory")}return dbFactory, nil
}
func GetSearchFactoryOr(opts *options.EsOptions) (v12.SearchFactory, error) {if opts == nil && searchFactory == nil {return nil, errors.New("failed to get es client")}once.Do(func() {esOpt := db.EsOptions{Host: opts.Host,Port: opts.Port,}esClient, err := db.NewEsClient(&esOpt)if err != nil {return}searchFactory = &dataSearch{esClient: esClient,}})if searchFactory == nil {return nil, errors.New("failed to get es client")}return searchFactory, nil
}
3.2编写wire.go文件
//go:build wireinject
// +build wireinjectpackage srvimport ("github.com/google/wire"v1 "mxshop/app/goods/srv/internal/controller/v1""mxshop/app/goods/srv/internal/data/v1/data_search/v1/es""mxshop/app/goods/srv/internal/data/v1/db"v12 "mxshop/app/goods/srv/internal/service/v1""mxshop/app/pkg/options"gapp "mxshop/gmicro/app""mxshop/pkg/log"
)func initApp(*log.Options, *options.ServerOptions, *options.RegistryOptions,*options.TelemetryOptions, *options.MySQLOptions, *options.EsOptions) (*gapp.App, error) {wire.Build(NewGoodsAppWire,NewRegistrar,NewGoodsRPCServerWire,v1.NewGoodsServerWire,v12.NewGoodsServiceWire,db.GetDBFactoryOr,es.GetSearchFactoryOr,)return &gapp.App{}, nil
}

3.3生成wire_gen.go文件

在这里插入图片描述

生成后的文件如下:

// Code generated by Wire. DO NOT EDIT.//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinjectpackage srvimport (v1_2 "mxshop/app/goods/srv/internal/controller/v1""mxshop/app/goods/srv/internal/data/v1/data_search/v1/es""mxshop/app/goods/srv/internal/data/v1/db""mxshop/app/goods/srv/internal/service/v1""mxshop/app/pkg/options""mxshop/gmicro/app""mxshop/pkg/log"
)// Injectors from wire.go:func initApp(logOptions *log.Options, serverOptions *options.ServerOptions, registryOptions *options.RegistryOptions, telemetryOptions *options.TelemetryOptions, mySQLOptions *options.MySQLOptions, esOptions *options.EsOptions) (*app.App, error) {registrar := NewRegistrar(registryOptions)dataFactory, err := db.GetDBFactoryOr(mySQLOptions)if err != nil {return nil, err}searchFactory, err := es.GetSearchFactoryOr(esOptions)if err != nil {return nil, err}serviceFactory := v1.NewGoodsServiceWire(dataFactory, searchFactory)goodsServer := v1_2.NewGoodsServerWire(serviceFactory)server, err := NewGoodsRPCServerWire(telemetryOptions, serverOptions, goodsServer)if err != nil {return nil, err}appApp, err := NewGoodsAppWire(logOptions, registrar, serverOptions, server)if err != nil {return nil, err}return appApp, nil
}

在如下方法替换接口

在这里插入图片描述

运行main.go文件,如下显示,正常启动

在这里插入图片描述

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

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

相关文章

Vue3封装一个轮播图组件

先看效果 编写组件代码 CarouselChart.vue <template><div classimg-box><el-button clickpreviousImages v-ifprops.showBtn>←</el-button><div classimg><div styledisplay: flex;gap: 20px idmove><imgclassimg-item v-for(item…

C语言--clock()时间函数【详细介绍】

一.clock()时间函数介绍 在 C/C 中&#xff0c;clock() 函数通常用于处理和测量程序运行时间&#xff08;时钟时间&#xff09;。它是一种数据类型&#xff0c;表示 CPU 执行指定任务所耗费的“时钟计数”数量&#xff0c;单位为“时钟周期”。 这个函数通常包含在 time.h 头文…

每日一题,头歌平台c语言题目

任务描述 题目描述:输入一个字符串&#xff0c;输出反序后的字符串。 相关知识&#xff08;略&#xff09; 编程要求 请仔细阅读右侧代码&#xff0c;结合相关知识&#xff0c;在Begin-End区域内进行代码补充。 输入 一行字符 输出 逆序后的字符串 测试说明 样例输入&…

大语言模型有什么意义?亚马逊训练自己的大语言模型有什么用?

近年来&#xff0c;大语言模型的崭露头角引起了广泛的关注&#xff0c;成为科技领域的一项重要突破。而在这个领域的巅峰之上&#xff0c;亚马逊云科技一直致力于推动人工智能的发展。那么&#xff0c;作为一家全球科技巨头&#xff0c;亚马逊为何会如此注重大语言模型的研发与…

解决夜神模拟器与Android studio自动断开的问题

原因&#xff1a;夜神模拟器的adb版本和Android sdk的adb版本不一致 解决办法&#xff1a; 1.找到android的sdk &#xff08;1&#xff09;File--->Project Structure (2)SDK Location:记下sdk的位置 2.找到sdk中的adb文件 SDK-->platform-tools-->adb.exe 3.复制…

通用的AGI 安全风险

传统安全风险 平台基础设施安全风险 模型与数据层安全风险 应用层安全风险 平台基础设施安全风险 &#xff08;1&#xff09;物理攻击&#xff1a;机房管控不到位 &#xff08;2&#xff09;网络攻击 &#xff08;3&#xff09;计算环境&#xff1a;自身安全漏洞&#xf…

基于大语言模型的复杂任务认知推理算法CogTree

近日&#xff0c;阿里云人工智能平台PAI与华东师范大学张伟教授团队合作在自然语言处理顶级会议EMNLP2023上发表了基于认知理论所衍生的CogTree认知树生成式语言模型。通过两个系统&#xff1a;直觉系统和反思系统来模仿人类产生认知的过程。直觉系统负责产生原始问题的多个分解…

Springboot入门篇

一、概述 Spring是一个开源框架&#xff0c;2003 年兴起的一个轻量级的Java 开发框架&#xff0c;作者Rod Johnson 。Spring是为了解决企业级应用开发的复杂性而创建的&#xff0c;简化开发。 1.1对比 对比一下 Spring 程序和 SpringBoot 程序。如下图 坐标 Spring 程序中的…

【Hadoop_04】HDFS的API操作与读写流程

1、HDFS的API操作1.1 客户端环境准备1.2 API创建文件夹1.3 API上传1.4 API参数的优先级1.5 API文件夹下载1.6 API文件删除1.7 API文件更名和移动1.8 API文件详情和查看1.9 API文件和文件夹判断 2、HDFS的读写流程&#xff08;面试重点&#xff09;2.1 HDFS写数据流程2.2 网络拓…

软件设计师——软件工程(一)

&#x1f4d1;前言 本文主要是【软件工程】——软件设计师——软件工程的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304…

phpstorm中使用 phpunit 时的配置和代码覆盖率测试注意点

初始化一个composer项目&#xff0c;composer.json配置文件如下 {"name": "zingfront/questions-php","type": "project","require": {"php": "^7.4"},"require-dev": {"phpunit/phpun…

Mac安装DevEco Studio

下载 首先进入鸿蒙开发者官网&#xff0c;顶部导航栏选择开发->DevEco Studio 根据操作系统下载不同版本&#xff0c;其中Mac(X86)为英特尔芯片&#xff0c;Mac(ARM)为M芯片。 安装 下载完毕后&#xff0c;开始安装。 点击Agree 首次使用&#xff0c;请选择Do not impor…

张驰咨询:数据驱动的质量改进,六西格玛绿带在汽车业实践

尊敬的汽车行业同仁们&#xff0c;您是否曾面临生产效率低下、成本不断攀升或顾客满意度下降的困扰&#xff1f;本期专栏&#xff0c;我们将深入探讨如何通过六西格玛绿带培训&#xff0c;在汽车行业中实现过程优化和质量提升。 汽车行业的竞争日趋激烈&#xff0c;致力于提供…

Flask维护者:李辉

Flask维护者&#xff1a;李辉&#xff0c; 最近看b站的flask相关&#xff0c;发现了这个视频&#xff1a;[PyCon China 2023] 濒危 Flask 扩展拯救计划 - 李辉_哔哩哔哩_bilibili 李辉讲他在维护flask之余&#xff0c;开发了apiflask这个依托flask的框架。GitHub - apiflask/a…

融合科技,升级医疗体验——医院陪诊服务的技术创新

随着科技的迅猛发展&#xff0c;医疗服务领域也在积极借助技术手段提升患者体验。本文将探讨如何利用先进的技术代码&#xff0c;将医院陪诊服务推向新的高度。 1. 医疗预约系统的实现 # 通过Python代码实现医疗预约系统 class MedicalAppointment:def __init__(self, patie…

基于轻量级神经网络GhostNet开发构建光伏太阳能电池缺陷图像识别分析系统

工作中经常会使用到轻量级的网络模型来进行开发&#xff0c;所以平时也会常常留意使用和记录&#xff0c;在前面的博文中有过很多相关的实践工作&#xff0c;感兴趣的话可以自行移步阅读即可。 《移动端轻量级模型开发谁更胜一筹&#xff0c;efficientnet、mobilenetv2、mobil…

python的websocket方法教程

WebSocket是一种网络通信协议&#xff0c;它在单个TCP连接上提供全双工的通信信道。在本篇文章中&#xff0c;我们将探讨如何在Python中使用WebSocket实现实时通信。 websockets是Python中最常用的网络库之一&#xff0c;也是websocket协议的Python实现。它不仅作为基础组件在…

NSSCTF web刷题记录7

文章目录 [SDCTF 2022]CURL Up and Read[NUSTCTF 2022 新生赛]Translate [SDCTF 2022]CURL Up and Read 考点&#xff1a;SSRF 打开题目发现是curl命令&#xff0c;提示填入url 尝试http://www.baidu.com&#xff0c;成功跳转 将url的字符串拿去解码&#xff0c;得到json格式数…

低功耗模式的通用 MCU ACM32F0X0 系列,具有高整合度、高抗干扰、 高可靠性的特点

ACM32F0X0 系列是一款支持多种低功耗模式的通用 MCU。集成 12 位 1.6 Msps 高精度 ADC 以及比 较器、运放、触控按键控制器、段式 LCD 控制器&#xff0c;内置高性能定时器、多路 UART、LPUART、SPI、I2C 等丰富的通讯外设&#xff0c;内建 AES、TRNG 等信息安全模块&#xff0…

云降水物理基础

云降水物理基础 云的分类 相对湿度变化方程 由相对湿度的定义&#xff0c;两边取对数之后可以推出 联立克劳修斯-克拉佩龙方程&#xff08;L和R都为常数&#xff09; 由右式看出&#xff0c;增加相对湿度的方式&#xff1a;增加水汽&#xff08;de增大&#xff09;和降低…