go程序中加载go编写的插件

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wyy626562203/article/details/83791169

go程序中加载go编写的插件

golang版本: 1.5 以上支持动态库,1.8以上支持plugin

go提供的plugin包可以实现热更新的功能。

Go插件是使用-buildmode = plugin标记编译的一个包,用于生成一个共享对象(.so)库文件。 Go包中的导出的函数和变量被公开为ELF符号,可以使用plugin包在运行时查找并绑定ELF符号。

Go编译器能够使用build flag -buildmode = c-shared创建C风格的动态共享库。

从1.8版开始,Go插件功能只能在Linux上使用。 很有可能在将来的版本中发生变化。

plugin

Plugin

type Plugin即Golang加载的插件,与之有关的两个方法:

  • Open: 根据参数path提供的插件路径加载这个插件,并返回插件这个插件结构的指针*Glugin
  • Lookup: *Plugin的惟一方法,通过名称symName在插件中寻找对应的变量或方法,以Symbol的形式返回

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

猜你喜欢

转载自blog.csdn.net/wyy626562203/article/details/83791169
go