重要
利用 Go 的 init() 函数 + 匿名导入(_ "pkg")实现编译期插件注册。新增插件只需写一个包并在入口处 import。
环境说明
项目结构:
1
2
3
4
5
6
7
8
9
10
11
| src/
└── example/
├── main.go
└── adaptor/
├── init.go ← 接口定义 + 注册表
├── standard/
│ └── imports.go ← 统一导入所有插件
├── cls1/
│ └── base.go ← 插件 1
└── cls2/
└── base.go ← 插件 2
|
完整代码
1. 定义接口和注册表
adaptor/init.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
| package adaptor
type Adaptors interface {
CreateUser(user string) (bool, error)
DeleteUser(user string) (bool, error)
Policies() (bool, error)
}
var FactoryByName = make(map[string]func() Adaptors)
func Register(name string, factory func() Adaptors) {
FactoryByName[name] = factory
}
|
2. 编写插件
adaptor/cls1/base.go:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| package cls1
import "example/adaptor"
type Cls1 struct{ Name string }
func (g *Cls1) CreateUser(user string) (bool, error) {
return true, nil
}
func (g *Cls1) DeleteUser(user string) (bool, error) {
return true, nil
}
func (g *Cls1) Policies() (bool, error) {
return true, nil
}
// init() 在包被导入时自动执行,将插件注册到全局表
func init() {
adaptor.Register("Cls1", func() adaptor.Adaptors {
return new(Cls1)
})
}
|
3. 统一导入
adaptor/standard/imports.go:
1
2
3
4
5
6
| package standard
import (
_ "example/adaptor/cls1"
_ "example/adaptor/cls2"
)
|
4. 入口文件
1
2
3
4
5
6
7
8
9
10
11
| package main
import (
_ "example/adaptor/standard" // 触发所有插件的 init()
)
func main() {
// FactoryByName 中已有 cls1、cls2
plugin := adaptor.FactoryByName["Cls1"]()
plugin.CreateUser("test")
}
|
5. 新增插件
- 创建
adaptor/cls-new/base.go——实现接口 + init() 注册 - 在
adaptor/standard/imports.go 中增加 _ "example/adaptor/cls-new"
无需修改 main.go 或 init.go。
参考