# Gone的核心概念

“我们编写的代码,终究只是死物,除非他在 天国(程序)复活(对Goners完成依赖的装配),为此我们需要将他 埋葬(注册)墓园(Gone内部的Goners仓库)。”

# Goner

Goner 是指实现了 gone.Goner 接口的结构体实例指针;只有实现了gone.Goner接口的实例才能被注册到Gone中;实现Goner接口 有且只有 通过嵌入 gone.Flag 来实现。

举个例子,下面的worker就是一个goner:

type Worker struct {
	gone.Flag
}
worker := &Worker{}

Goner是Gone的组件,是实现依赖注入的关键:

  1. Goner可以作为值被注入到其Goner的属性;
  2. Goner的属性可以被其Goners注入。

为什么只能内嵌 `gone.Flag`实现**Goner**接口?

下面是Goner和gone.Flag的源代码:

type Flag struct{}
func (g *Flag) goneFlag() {}
//...
// Goner 逝者
type Goner interface {
	goneFlag()
}

Goner作为接口,要求实现它的“对象”拥有一个私有的方法goneFlag();由于go语言可见性的限制,不能在github.com/gone-io/gone以外的包中实现其内部定义的私有方法;一个结构体要成为Goner,只能通过内嵌gone.Flag才能“继承”私有的方法goneFlag()。这段话可能有些不好理解,其实就是说Goner的实现只能通过内嵌gone.Flag来完成,不能通过实现goneFlag()方法来完成。

提示

多个Goner,我们使用其复数形式(Goners)表示。

# 特殊Goners

# 🔮Prophet(先知,率先知道装配完成)

一种特殊的 Goner,在普通 Goner 上实现了 AfterRevive() AfterReviveError 方法就是 Prophet(先知)AfterRevive 会在所有 Goners 都完成依赖注入装配流程后被执行。

Prophet接口定义如下:

// Prophet  先知
type Prophet interface {
	Goner
	//AfterRevive 在所有Goners装配完后会被执行
	AfterRevive() error
}

# 😇Angel(天使,看护开始和结束)

一种特殊的 Goner,拥有天使左翼Start(Cemetery) error 和 天使右翼Stop(Cemetery) error,左翼负责开始(用于分配资源,启动某项服务),右翼负责结束(用于终止某项服务,回收资源)。

Angel接口定义如下:

type Angel interface {
	Goner
	Start(Cemetery) error
	Stop(Cemetery) error
}

# 🧛🏻‍♀️Vampire(吸血鬼,扩展注入类型)

一种特殊的 Goner,拥有特殊能力——“吸血”Suck(conf string, v reflect.Value) SuckErrorSuck可以将不是Goner的值赋予注入给Goner属性。

Vampire接口定义如下:

type SuckError error
type Vampire interface {
	Goner
	Suck(conf string, v reflect.Value) SuckError
}

# Cemetery(Goners仓库)

Cemetery用于管理Goners,主要提供Bury(注册)和 revive(装配)的方法,其接口定义如下:

type Cemetery interface {
	// ... 其他方法
	Goner
	Bury(Goner, ...GonerId) Cemetery  // 将Goner注册到框架
	//ReviveAllFromTombs 装配所有Goner
	ReviveAllFromTombs() error
	//...
}

从代码上可以看到Cemetery本身也是一个Goner,在Gone框架启动时他自己也注册到Cemetery中。

# Bury(注册)

将Goner 注册Cemetery(goners仓库) 就是将Goner注册到框架,以待装配流程完成属性的注入;在代码实现上,BuryCemetery上的公开方法,一般在通过 Priest 函数调用该方法。

# Revive(装配)

Revive(装配)指的是Goner所有需要注入的属性完成依赖装配的过程。在函数ReviveAllFromTombs() error中,尝试装配所有被注册的Goners,如果存在属性不能正常注入,程序将抛出panic。

提示

ReviveAllFromTombs在完成了装配所有的Goners后,会调用所有ProphetAfterRevive方法。

# Heaven

Heaven(天国)代表了一个Gone程序,用于管理程序的启动、停止等状态和流程(装配在启动前完成),用于在启动前后以及程序停止前执行一些hook任务。Heaven接收一个牧师函数开始运行,例如:

package main
import "github.com/gone-io/gone"
func Priest(cemetery gone.Cemetery) error {
	// 调用 cemetery.Bury 注册 Goner
	// 或者 调用其他 Priest 函数
	// TODO
	return nil
}
func main(){
	gone.Run(Priest)
}

或者:

package main
import "github.com/gone-io/gone"
func Priest(cemetery gone.Cemetery) error {
	// 调用 cemetery.Bury 注册 Goner
	// 或者 调用其他 Priest 函数
	// TODO
	return nil
}
func main(){
	gone.
		Prepare(Priest).
		AfterStart(func(){
			//TODO: 启动后执行一些操作
		}).
		Run()
}

# Priest (批量注册Goners)

Priest (牧师)是负责将Goner注册到Gone的函数,他的定义如下:

type Priest func(cemetery Cemetery) error

Priest函数实现上,可以调用 cemetery.Bury 来完成,如下:

type Worker struct {
	gone.Flag
	Name string
}
type Boss struct {
	gone.Flag
	Name string
}
func aPriest(cemetery gone.Cemetery) error {
	cemetery.Bury(&Boss{Name: "Jim"}, "boss-jim")
	cemetery.Bury(&Worker{Name: "Bob"}, "worker-bob")
	//匿名注册,不指定被注册Goner的GonerId
	cemetery.Bury(&Worker{Name: "X"})
	return nil
}
//...

也可以通过调用其他的Priest函数来完成:

func a1Priest(cemetery gone.Cemetery) error {
	//todo
	return nil
}
func a2Priest(cemetery gone.Cemetery) error {
	//todo
	return nil
}
func aPriest(cemetery gone.Cemetery) error {
	_ = a1Priest(cemetery)
	_ = a2Priest(cemetery)
	//todo
	return nil
}

如果开发了一个组件包使用了多个Goners来实现相应的功能;使用时需要同时注册多个Goners,可能不是那么方便;为了方便用户使用我们开发的包,可以编写一个Priest函数批量注册Goners。

Gone内置的组件包,我们就是这样做的,可以参考代码 (opens new window)文档 (opens new window)

另外,我们开发了一个命令行辅助工具 gone (opens new window),用于扫描特殊注释//go:gone自动生成牧师函数,参考 自动生成Priest

# 总结

在Gone中,组件叫Goner(逝者),称为Goner需要嵌入gone.Flag(死亡标记),Goner被注册(埋在)到 Cemetery(墓园)中;Gone启动时,自动装配(Revive)所有Goners,建立一个天国(Gone程序),在天国中有先知、天使和吸血鬼。

是不是很有意思呢?