go微服务框架kratos学习笔记八(kratos的依赖注入)


笔记二提过依赖注入,和如何生成,但没有细讲,本文来简单看看kratos的依赖注入。

什么是依赖注入

先来看一个小程序,

创建一个小程序模拟迎宾员问候客人的事件

我们将创建三个结构类型:

1)为迎宾员创建消息 message

2)表达消息的迎宾员 greeter

3)迎宾员问候客人的事件 event

type Message string

type Greeter struct {
// ... TBD
} type Event struct {
// ... TBD
}

Message 仅仅携带一条string,现在我们创建一个简单初始器

func NewMessage() Message {
return Message("Hi there!")
}

我们的Greeter将需要引用这条消息,让我们创建一条初始器给Greeter

func NewGreeter(m Message) Greeter {
return Greeter{Message: m}
} type Greeter struct {
Message Message // <- adding a Message field
}

在这个初始器中我们分配了Message 字段给Greeter,现在我们能用Greeter的方法Greet来得到一条Message

func (g Greeter) Greet() Message {
return g.Message
}

下一步,我们同样也需要一个初始器用Event来创建一个Greeter

func NewEvent(g Greeter) Event {
return Event{Greeter: g}
} type Event struct {
Greeter Greeter // <- adding a Greeter field
}

添加一个Start()来启动事件

func (e Event) Start() {
msg := e.Greeter.Greet()
fmt.Println(msg)
}

Start即是我们小程序的核心,它告诉greeter去放出一条问候并打印出来。

现在我们小程序所有的组件就绪了,看看它是如何初始化所有组件的,它看起来可能是这样的

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

首先我们创建一条message,然后我们用message创建一个greeter,最后我们用greeter创建一个event.

这其实就是依赖注入dependency injection简称di的原理,

依赖注入基本上就是提供对象需要的对象(其依赖),而不是让对象自己构造它们。

依赖注入能让测试变的更为简单,我们可以通过构造函数来进行注入。

SomeClass() has its constructor as following:

public SomeClass() {
myObject = Factory.getObject();
}

例如,如果myObject包含复杂的任务像磁盘访问或者网络访问,那么SomeClass将很难进行单元测试。程序必须模仿myObject并且需要模仿Factory调用

而将myObject作为参数传递给构造函数.

public SomeClass (MyClass myObject) {
this.myObject = myObject;
}

myObject就能直接运行,使测试变的更为简单。

可以通过多种方式将依赖项注入到对象中(例如构造函数注入或setter注入)。甚至可以使用专门的依赖项注入框架(例如Spring)来做到这一点,但是肯定不是必需的。不需要那些框架的依赖注入。显式实例化和传递对象(依赖项)与框架注入一样好。

google wire

kratos 使用的 google wire 就是golang的一个依赖注入解决的工具,这个工具能够自动生成类的依赖关系。

依赖注入的一个缺点就是需要如此多的初始化步骤,让我们看看如何使用Wire来让初始化我们的组件变的更快.

将我们的小程序main函数改成如下形式:

func main() {
e := InitializeEvent() e.Start()
}

下一步,分离一个文件wire.go,我们定义InitializeEvent

// wire.go

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

不是依次初始化每个组件并将其传递给下一个组件,而是通过一个 wire.Build调用来构建我们想要的用的初始器。在Wire中,初始化器被称为providers,一个提供特定类型的函数。

我们为Event添加一个零值作为返回值,以满足编译器的要求。

注意,即使我们向Event添加值,Wire也会忽略它们。

实际上,注入器的目的是提供关于使用哪些providers 来构造Event的信息。

InitializeEvent即是一个“注入器”。现在我们已经完成了注入器

然后在wire.go目录下运行wire工具。

安装

go get github.com/google/wire/cmd/wire

Wire将找到InitializeEvent注入器并生成一个函数,其主体由所有必要的初始化步骤填充。结果将被写入名为wire_gen.go的文件。

// wire_gen.go

func InitializeEvent() Event {
message := NewMessage()
greeter := NewGreeter(message)
event := NewEvent(greeter)
return event
}

这看上去就像我们上面手工写的代码,想象一下,对于复杂得多的组件,Wire是多么有用。

kratos中的wire

最后回来看看kratos中的wire.go

// +build wireinject
// The build tag makes sure the stub is not built in the final build. package di import (
pb "demo/api"
"demo/internal/dao"
"demo/internal/server/grpc"
"demo/internal/server/http"
"demo/internal/service" "github.com/google/wire"
) var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC)
var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service))) func InitApp() (*App, func(), error) {
panic(wire.Build(daoProvider, serviceProvider, http.New, grpc.New, NewApp))
}

可以看到kratos用到了wire的一些其它接口:wire.NewSet,wire.Bind,简单看看。

wire.NewSet

Wire有两个核心概念:Providers injectors

Providers

Wire中的主要机制是Providers :一个可以生成值的函数。这些函数都是普通的Go代码。

Providers 可以分组为provider sets,通过wire.NewSet 函数可以添加一组providers 到一个新的集合中。

var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC)

当然也可以添加一个provider sets进一个provider sets

var MegaSet = wire.NewSet(daoProvider, pkg.OtherSet)

injector(注入器)

一个应用程序用injector连接这些providers: 一个按依赖顺序调用providers的函数,即使用Wire,编写注入器的签名,然后Wire生成函数的主体。

调用wire.Build的函数则是来声明注入器的,返回值不重要,只要类型正确即可。

func InitApp() (*App, func(), error) {
panic(wire.Build(daoProvider, serviceProvider, http.New, grpc.New, NewApp))
}

Binding Interfaces

最后看看 wire.Bind 用来绑定接口的具体类型。

var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service)))

wire.Bind第一个参数 为指向所需接口类型的指针,第二个参数为 指向实现该接口类型的指针,

可以看到如果不加wire.Bind(new(pb.DemoServer), new(*service.Service)), 可以看到会找不到依赖。

go微服务框架kratos学习笔记八 (kratos的依赖注入)的更多相关文章

  1. go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时])

    目录 go微服务框架kratos学习笔记五(kratos 配置中心 paladin config sdk [断剑重铸之日,骑士归来之时]) 静态配置 flag注入 在线热加载配置 远程配置中心 go微 ...

  2. # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...

  3. go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer)

    目录 go微服务框架kratos学习笔记七(kratos warden 负载均衡 balancer) demo demo server demo client 池 dao service p2c ro ...

  4. go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用)

    目录 go微服务框架kratos学习笔记四(kratos warden-quickstart warden-direct方式client调用) warden direct demo-server gr ...

  5. go微服务框架kratos学习笔记九(kratos 全链路追踪 zipkin)

    目录 go微服务框架kratos学习笔记九(kratos 全链路追踪 zipkin) zipkin使用demo 数据持久化 go微服务框架kratos学习笔记九(kratos 全链路追踪 zipkin ...

  6. 微服务框架surging学习之路——序列化 (转载https://www.cnblogs.com/alangur/p/10407727.html)

    微服务框架surging学习之路——序列化   1.对微服务的理解 之前看到在群里的朋友门都在讨论微服务,看到他们的讨论,我也有了一些自己的理解,所谓微服务就是系统里的每个服务都 可以自由组合.自由组 ...

  7. golang微服务框架go-micro 入门笔记2.4 go-micro service解读

    本章节阐述go-micro 服务发现原理 go-micro架构 下图来自go-micro官方 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

  8. golang微服务框架go-micro 入门笔记2.3 micro工具之消息接收和发布

    本章节阐述micro消息订阅和发布相关内容 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架go-mi ...

  9. golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

    micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

随机推荐

  1. 深入理解vue的watch

    深入理解vue的watch vue中的wactch可以监听到data的变化,执行定义的回调,在某些场景是很有用的,本文将深入源码揭开watch额面纱 前言 watch的使用 watch的多种使用方式 ...

  2. 【转】ArcGIS Server 10.1 动态图层—更改风格

    在 ArcGIS Server REST API中我们可以通过向Graphicslayer中添加临时图元的方法来完成对显示结果的渲染:如果仅仅是更改原有地图服务显示风格,在ArcGIS10.1下使用动 ...

  3. Java集合框架(java.util包)

    集合的概念: 是一种工具类,可以存储任意数量.任意类型的对象(所以后面需要用到泛型,以约束集合中元素的类型) 集合的作用: 1.在类的内部对属性进行组织 2.方便快速定位属性位置 3.某些集合接口,提 ...

  4. Date类(java.util)和SimpleDateFormat类(java.text)

    在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Date 类.这个类最主要的作用就是获取当前时间,我们来看下 Date 类的使用: 使用 Date 类的默 ...

  5. react入门(六):状态提升&context上下文小白速懂

    一.状态提升 使用 react 经常会遇到几个组件需要共用状态数据的情况.这种情况下,我们最好将这部分共享的状态提升至他们最近的父组件当中进行管理. 原理:父组件基于属性把自己的一个fn函数传递给子组 ...

  6. Git高级之配置多个SSH key

    最近我们在代码托管平台上使用SSH的方式下拉代码,通常是用一个ssh key来拉取所有托管平台的代码,如码云,GitHub.GitLab等,但是总用一个不是太好.会有安全风险,这就需要为每个托管平台设 ...

  7. KMO检验和Bartlett球形检验

    KMO检验和Bartlett球形检验因子分析前,首先进行KMO检验和巴特利球体检验,KMO检验系数>0.5,(巴特利特球体检验的x2统计值的显著性概率)P值<0.05时,问卷才有结构效度, ...

  8. cocoa pods最新安装说明和使用方法

    最新版 CocoaPods 的安装流程 1.移除现有Ruby默认源 $gem sources --remove https://rubygems.org/ 2.使用新的源 $gem sources - ...

  9. java8新特性Lambda和Stream

    Java8出来已经4年,但还是有很多人用上了jdk8,但并没用到里面的新东西,那不就等于没用?jdk8有许多的新特性,详细可看下面脑图 我只讲两个最重要的特性Lambda和Stram,配合起来用可以极 ...

  10. java中5种异步转同步方法

    先来说一下对异步和同步的理解: 同步调用:调用方在调用过程中,持续等待返回结果. 异步调用:调用方在调用过程中,不直接等待返回结果,而是执行其他任务,结果返回形式通常为回调函数. 其实,两者的区别还是 ...