目录
Please enable Javascript to view the contents

Go Module 实现插件机制

 ·  ☕ 2 分钟

重要

利用 Go 的 init() 函数 + 匿名导入(_ "pkg")实现编译期插件注册。新增插件只需写一个包并在入口处 import

环境说明

  • Go 1.20

项目结构:

 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. 新增插件

  1. 创建 adaptor/cls-new/base.go——实现接口 + init() 注册
  2. adaptor/standard/imports.go 中增加 _ "example/adaptor/cls-new"

无需修改 main.goinit.go

参考

分享

Hex
作者
Hex
CloudNative Developer