Gone支持的依赖注入方式

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 在Go中,依赖注入通过`gone`标签实现,标记有`gone`的结构体字段在Gone启动时接收依赖。支持值类型、指针类型、接口类型、slice及map类型的注入,但值类型不推荐因拷贝导致独立内存。GonerId用于具名注入,允许可选的GonerId在注册时指定,私有属性也可注入以降低耦合。

为了区分结构体属性是否需要依赖注入,我们引入一个标签——gone,拥有gone标签的属性将在Gone启动过程中被注入需要的依赖。

支持的属性类型

值类型

结构体的属性为某个机构体的值类型,如下面代码中的Boss.Seller

go

复制代码

type Worker struct {
	gone.Flag
	Name      string
}

type Boss struct {
    gone.Flag
    Seller  Worker `gone:"*"`  //值类型
}

::: warning 注意:不推荐使用值类型做注入 “值类型 的赋值和传参都是传递的拷贝”,这意味着我们如果使用 值类型 注入时,实际上产生了一个新的“对象”,新分配了一块内存,并且新旧对象只有在“传递那一刻”是相等,他们在内存中是独立的;这可能导致一些不符合“直觉”的结果,举个例子:

go

复制代码

type BGoner struct {
	gone.Flag

	a1 AGoner  `gone:"A1"` // 值注入
	a2 AGoner  `gone:"A1"` // 值注入
}

func (g *BGoner) AfterRevive() gone.AfterReviveError {
	g.a1.Name = "dapeng"
	g.a2.Name = "wang"

	fmt.Printf("a1 is eq a2: %v", g.a1 == g.a2)

	return nil
}

在上面的代码中,打印的结果会是 false。 :::

指针类型

接收注入的结构体属性是另一个结构体的指针,如下面代码的Boss.Seller的类型为 *Worker:

go

复制代码

type Worker struct {
	gone.Flag
	Name      string
}

type Boss struct {
    gone.Flag
    Seller  *Worker `gone:"*"`  //指针类型
}

接口类型

接收注入的结构体属性是一个接口,如下面代码的Boss.Seller的类型为 Seller,Gone会从注册的Goners中查找实现了Seller接口的Goner赋值给Boss.Seller

go

复制代码

type Seller interface {
    Sell() error
}

type Boss struct {
    gone.Flag
    Seller Seller `gone:"*"`  //接口类型
}

slice 类型

接收注入的结构体属性还可以是 slice 类型,slice 的元素类型允许为 值类型(由于值拷贝,不推荐使用)、指针类型 和 接口类型,如下代码中的Boss.SellersBoss.WorkersBoss.Persons,Gone会尝试间类型兼容的所有goners添加到slice中。

go

复制代码

type Worker struct {
	gone.Flag
	Name      string
}

type Seller interface {
    Sell() error
}

type Boss struct {
    gone.Flag
    Sellers []Seller  `gone:"*"`  //Slice 类型,元素为接口类型
    Workers []*Worker `gone:"*"`   //Slice 类型,元素为指针类型
    Persons []Worker  `gone:"*"`   //Slice 类型,元素为值类型
}

map 类型

接收注入的结构体属性还可以是 map 类型,map 的元素类型允许为 值类型(由于值拷贝,不推荐使用)、指针类型 和 接口类型。map 的 key 只能被定义为string类型,被注入后map key 的值为 GonerId(后面介绍什么是GonerId)。

举个例子

go

复制代码

type Worker struct {
	gone.Flag
	Name      string
}

type Seller interface {
    Sell() error
}

type Boss struct {
    gone.Flag
    Sellers map[string]Seller  `gone:"*"`  //Map 类型,元素为接口类型
    Workers map[string]*Worker `gone:"*"`   //Map 类型,元素为指针类型
    Persons map[string]Worker  `gone:"*"`   //Map 类型,元素为值类型
}

GonerId 和 具名注入

GonerId

Goner注册到Gone框架,支持传递一个可选参数GonerId,如果不传也会随机生成一个,如下:

go

复制代码

type Worker struct {
	gone.Flag
	Name      string
}

type Seller interface {
    Sell() error
}

type Boss struct {
    gone.Flag
    Sellers map[string]Seller  `gone:"*"`  //Map 类型,元素为接口类型
    Workers map[string]*Worker `gone:"*"`   //Map 类型,元素为指针类型
    Persons map[string]Worker  `gone:"*"`   //Map 类型,元素为值类型
}


func Priest(cemetery gone.Cemetery) error {
	cemetery.
		Bury(&Worker{}, gone.GonerId("worker-01")). //注册;使用worker-01做GonerId
		Bury(&Worker{}, gone.GonerId("worker-02")). //注册;使用worker-02做GonerId
		Bury(&Boss{}) //匿名注册,不关心GonerId是什么
	return nil
}

具名注入

前面的例子中,依赖注入标记gone的值都是*,意思让Gone自动寻找或者构建兼容的类型完成注入,我们称之为 匿名注入。另外,Gone支持在gone标签赋予一个值作为GonerId,要求Gone查找特定GonerId的Goner完成依赖注入,也就是 具名注入

如下面代码中,Boss.Manager的注入,Gone会自动寻找GonerId为worker-01的Goner,完成注入。

go

复制代码

type Boss struct {
	gone.Flag
	Manager *Worker `gone:"worker-01"` //具名注入
}

私有属性注入

前面的例子中,所有的属性都是 共有属性 (又称Exported,是大写字母打头的,在包外部可以访问的);Gone实际是支持在私有属性上完成依赖注入的,如下:

go

复制代码

type Boss struct {
	gone.Flag
	manager *Worker `gone:"worker-01"` //manager为私有属性也是可以的
}

我们推荐使用私有属性注入,因为被依赖注入的“对象”一般仅限于内部使用,使用私有属性注入,可以减少代码的耦合度,提高代码的可维护性。


转载来源:https://juejin.cn/post/7382891971858448423

相关文章
|
7月前
|
Java Spring
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
67 0
|
1月前
|
负载均衡 Java API
|
9月前
|
NoSQL Redis
如何用最简单的方式解释依赖注入?依赖注入是如何实现解耦的?
如何用最简单的方式解释依赖注入?依赖注入是如何实现解耦的?
36 0
|
11月前
|
容器
什么是依赖注入?有哪些注入方式?
什么是依赖注入?有哪些注入方式?
114 0
|
11月前
|
XML 敏捷开发 存储
spring框架-概述(spring特性、生命周期)(一)
spring框架-概述(spring特性、生命周期)(一)
|
缓存 Java Android开发
TheRouter 的跨模块依赖注入实现原理
`TheRouter`用于跨模块通信设计的`ServiceProvider`,核心设计思想是参考了SOA(面向服务架构)的设计方式。
116 0
TheRouter 的跨模块依赖注入实现原理
|
Java 数据库连接 Spring
Spring 核心功能之一【IoC容器】依赖注入接口,层级包命名规范
Spring 核心功能之一【IoC容器】依赖注入接口,层级包命名规范
121 0
Spring 核心功能之一【IoC容器】依赖注入接口,层级包命名规范
|
Java 关系型数据库 MySQL
【SpringBoot 基础系列】接口上注解 AOP 拦截不到场景兼容实例演示
在 Java 的开发过程中,面向接口的编程可能是大家的常态,切面也是各位大佬使用 Spring 时,或多或少会使用的一项基本技能;结果这两个碰到一起,有意思的事情就发生了,接口方法上添加注解,面向注解的切面拦截,居然不生效 这就有点奇怪了啊,最开始遇到这个问题时,表示难以相信;事务注解也挺多是写在接口上的,好像也没有遇到这个问题(难道是也不生效,只是自己没有关注到?) 接下来我们好好瞅瞅,这到底是怎么个情况
502 0
【SpringBoot 基础系列】接口上注解 AOP 拦截不到场景兼容实例演示
|
Java 容器 Spring
Spring Aop(十四)——Aop自动创建代理对象的原理
Aop自动创建代理对象的原理 我们在使用Spring Aop时,通常Spring会自动为我们创建目标bean的代理对象,以使用对应的Advisor。前提是我们在使用Spring Aop时是使用的或,这是因为当我们在applicationContext.xml文件中通过的形式定义需要使用Aop的场景时,Spring会自动为我们添加AspectjAwareAdvisorAutoProxyCreator类型的bean;而我们定义了时,Spring会默认为我们添加AnnotationAwareAspectjAutoProxyCreator类型的bean。
1852 0
|
Java API Spring
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(二)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(二)
102 0
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(二)

热门文章

最新文章