插件库导出信息需位于main包内
package main
import "fmt"
func init() {
fmt.Println("I'm in plugin init()")
}
func MyPrin(a, b int) int {
fmt.Println("I'm in plugin func")
return a + b
}
二、插件库打包
1·、go plugin 打包依赖gcc,如果环境没有安装gcc,需安装gcc
sudo apt-get install gcc
2、插件库打包,我打的库名包含了依赖的go版本1.19及库版本01
go build -buildmode=plugin -o myplugin-v1.19-01.so plugin.go
三、插件库调用
1、加载库,多次加载同一个库返回同一个库引用。
2、查找库导出信息,使用Lookup查找库导出信息。
3、类型转换,Lookup查询到的是抽象类型Symbol,需要转换为实际需要使用的类型。
4、实际类型调用。
package main
import (
"log"
"plugin"
)
func main() {
// 根据库的存放路径加载库
p, err := plugin.Open("myplugin.so")
if err != nil {
log.Fatal(err)
}
// 查找库导出信息
s, err := p.Lookup("MyPrin")
if err != nil {
log.Fatal(err)
}
// 类型转换
f := s.(func(a, b int) int)
// 实际类型调用
v := f(4, 5)
println(v)
}
四、增量部署与热部署
1、http服务,打包部署 go build main.go ,运行 ./main
package main
import (
"net/http"
"plugin"
)
func main() {
http.HandleFunc("/plugin", func(w http.ResponseWriter, r *http.Request) {
defer func() {
recover()
}()
values := r.URL.Query()
version := values.Get("version")
if version == "" {
w.Write([]byte("默认实现,更多精彩敬请期待"))
return
}
p, err := plugin.Open(version + ".so")
if err != nil {
w.Write([]byte("功能暂未上线,敬请期待"))
}
s, err := p.Lookup("MyPrin")
if err != nil {
w.Write([]byte("功能暂未上线,敬请期待"))
}
f := s.(func() string)
v := f()
w.Write([]byte(v))
})
http.ListenAndServe(":8080", nil)
}
2、模块1,打包 go build -buildmode=plugin -o myplugin-v1.so pluginv1.go
package main
import (
"fmt"
)
func init() {
fmt.Println("版本v1初始化")
}
func MyPrin() string {
return "版本v1应答"
}
3、模块2,打包 go build -buildmode=plugin -o myplugin-v2.so pluginv2.go
package main
import (
"fmt"
)
func init() {
fmt.Println("版本v2初始化")
}
func MyPrin() string {
return "版本v2应答"
}
4、访问 http://localhost:8080/plugin
默认实现,更多精彩敬请期待
5、http://localhost:8080/plugin?version=myplugin-v1
版本v1应答
6、http://localhost:8080/plugin?version=myplugin-v2
版本v2应答
7、http://localhost:8080/plugin?version=myplugin-v3
功能暂未上线,敬请期待
1、go插件目前支持Linux, FreeBSD, macOS。
2、go插件与调用者依赖的go版本及第三方库版本需要一致。
3、使用go plugin 动态库加载可以实现go项目的增量部署、插件热部署。