Go plugins 插件
插件开发
动态加载plugins,实现功能扩展、热加载. 但是存在一个问题,编译必须是同一个go版本
插件弱点
原生插件的弱点
- 编译的 Go 版本必须完全一致 - 事实上这个插件都可以不是由同一个人编写,要求编译的 Go 版本一致显然有点要求太高了
- 双方依赖的公共第三方库版本必须完全一致
- GOPATH 也得保持一致 - 不过这一点可以在编译时候使用 trimpath 参数解决
- 插件加载之后无法卸载
项目目录
1.
2├── Makefile
3├── README.md
4├── go.mod
5├── main.go
6└── plugins
7 ├── eng
8 │ └── speaker.go
9 └── vie
10 └── speaker.go
编译项目
1make
运行demo
1go run main.go vietnamese
2
3or
4
5go run main.go english
源码
- main.go
1package main
2
3import (
4 "errors"
5 "fmt"
6 "os"
7 "plugin"
8 "strings"
9)
10
11type Speaker interface {
12 Speak() string
13}
14
15func main() {
16 err := run(os.Args)
17 if err != nil {
18 fmt.Println(err.Error())
19 os.Exit(1)
20 }
21}
22
23func run(args []string) error {
24 lang := "english"
25 if len(args) == 2 {
26 lang = args[1]
27 }
28 var mod string
29 switch lang {
30 case "english":
31 mod = "./plugins/eng/speaker.so"
32 case "vietnamese":
33 mod = "plugins/vie/speaker.so"
34 default:
35 return errors.New("this speakerName is not supported")
36 }
37
38 plugin, err := plugin.Open(mod)
39 if err != nil {
40 return err
41 }
42
43 speaker, err := lookUpSymbol[Speaker](plugin, "Speaker")
44 if err != nil {
45 return err
46 }
47
48 speakerName, err := lookUpSymbol[string](plugin, "SpeakerName")
49 if err != nil {
50 return err
51 }
52 fmt.Printf("%s says \"%s\" in %s", *speakerName, (*speaker).Speak(), strings.Title(lang))
53 return nil
54}
55
56func lookUpSymbol[M any](plugin *plugin.Plugin, symbolName string) (*M, error) {
57 symbol, err := plugin.Lookup(symbolName)
58 if err != nil {
59 return nil, err
60 }
61 switch symbol.(type) {
62 case *M:
63 return symbol.(*M), nil
64 case M:
65 result := symbol.(M)
66 return &result, nil
67 default:
68 return nil, errors.New(fmt.Sprintf("unexpected type from module symbol: %T", symbol))
69 }
70}
- Makefile
1build-plugins:
2 $(foreach file, $(wildcard ./plugins/*), go build -buildmode=plugin -o $(file)/speaker.so $(file)/speaker.go;)
- plugins/eng/speaker.go
1package main
2
3type speaker struct {
4}
5
6func (s *speaker) Speak() string {
7 return "hello"
8}
9
10// Exported
11var Speaker speaker
12var SpeakerName = "Alice"
- plugins/vie/speaker.go
1package main
2
3type speaker struct {
4}
5
6func (s *speaker) Speak() string {
7 return "xin chào"
8}
9
10// Exported
11var Speaker speaker
12var SpeakerName = "Anh Thư"
评论