golang版本: 1.5 以上支持动态库,1.8以上支持plugin
go提供的plugin包可以实现热更新的功能。
-buildmode = plugin
build flag -buildmode = c-shared
从1.8版开始,Go插件功能只能在Linux上使用。 很有可能在将来的版本中发生变化。
plugin
Plugin
Plugin
Openpath*GluginLookup*PluginsymNameSymbol
Symbol
type Symbol interface{}Symbolinterface
插件实例
本例子有点复杂。
实现插件
插件代码的编写和普通的go模块代码一样,主要是package必须是 main。
类似c的头文件,定义一些数据
package data
type PluginData struct {
Name string
Age int
Tel string
}
var DataChan = make(chan PluginData)
记得函数名要大些不然无法被外部程序访问(init除外)
//testplugin.go
package main
import (
"fmt"
"data"
)
var Value int
var Pd data.PluginData
//init 函数的目的是在插件模块加载的时候自动执行一些我们要做的事情,
//比如:自动将方法和类型注册到插件平台、输出插件信息等等。Hello函数
//则是我们需要在调用方显式查找的symbol
func init() {
fmt.Println("plugin load...")
//我们还可以做其他更高阶的事情,比如
//platform.RegisterPlugin({"func": Hello}) 之类的,
//向插件平台自动注册该插件的函数
}
func Plugin_fun() {
fmt.Printf("Value in plugin: %d\n",Value)
}
func ComplexType() {
fmt.Println(Pd.Name, Pd.Age, Pd.Tel)
Pd.Age = Pd.Age * 4
data.DataChan<-Pd
}
编译插件
如果要想更好的控制插件的版本,想做更酷的事情,比如:热更新插件。那么可以采用自动注册的方式,新版本的插件加载上来后,自动注册插件版本号,插件平台里优先使用新版本的方法。
#编译go动态库命令,以当前目录名称作为动态库文件名
go build -buildmode=plugin
#编译go动态库命令,testPlugin作为动态库文件名
go build -buildmode=plugin testPlugin.go
#编译完后我们可以看到当前目录下有一个testplugin.so文件
#我们也可以通过类似如下命令来生成不同版本的插件
go build -o testplugin_v1.so -buildmode=plugin testPlugin.go
#创建C风格的动态共享库,可供c语言调用
#注意需要在testPlugin中实现main函数,否则无法编译
go build -buildmode=c-shared
go build -buildmode=c-shared testPlugin.go
使用插件
//main.go
package main
import (
"data"
"plugin"
)
func main() {
so, err := plugin.Open("testPlugin.so")
if err != nil {
panic(err)
}
value, err := so.Lookup("Value")
if err != nil {
panic(err)
}
plugin_fun, err := so.Lookup("Plugin_fun")
if err != nil {
panic(err)
}
*value.(*int) = 7
plugin_fun.(func())() // prints "Hello, number 7"
pd, err := so.Lookup("Pd")
if err != nil {
panic(err)
}
complexType, err := so.Lookup("ComplexType")
if err != nil {
panic(err)
}
*pd.(*data.PluginData) = data.PluginData{
Name: "PluginTest",
Age: 11,
Tel: "15396656998",
}
go complexType.(func())()
select {
case m := <-data.DataChan:
println(m.Age)
}
}
编译
go build main.go