golang 中 plugin 的使用
简介
- golang 是一门静态编译的语言,想要实现动态热更新是相对比较困难的
- 从
go 1.8
版本之后,官方提供了plugin
包来进行动态加载 - 他可以动态的加载so和执行导出的方法,并且仅仅提供了两个方法:打开模块和提取符号,甚至连关闭都没有(-_-)。
使用场景
- 可插拔:有了Plugin,我的程序可以根据需要随时替换其中某些部件而不用修改我的程序;
- 动态加载的需要:有些模块只有在运行时才能确定,需要动态加载外部的功能模块;
- 独立开发:Plugin 可以和主程序独立建设,主程序只需要制定好框架,实现默认(模版)功能。Plugin 可根据用户需求随时自行扩展开发,运行时随意替换,提高了程序的可定制性;
使用注意事项
- Plguin 需要有自己的 main package
- 编译的时候,使用 go build -buildmode=plugin file.go 来编译
- 使用 plugin.Open(path string) 来打开.so文件,同一插件只能打开一次,重复打开会报错
- 使用 plugin.LookUp(name string) 来获取插件中对外暴露的方法或者类型
- 使用类型断言,断言后执行相应的方法
简单例子
插件
plugin.go
1
2
3
4
5
6
7
8
9package main
import "fmt"
func main() {}
func GetProductBasePrice(basePrice int) int {
return basePrice + 200
}go build -buildmode=plugin plugin.go
命令编译出plugin.so
插件
调用
- main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("plugin.so")
if err != nil {
panic(err)
}
m, err := p.Lookup("GetProductBasePrice")
if err != nil {
panic(err)
}
res := m.(func(int) int)(30)
fmt.Println(res)
}
注意几点问题:
- 插件中定义的 struct 无法暴露出来,可以让主程序和插件程序import公共的 package 来解决
- 私有方法、变量不会被暴露出来