前言:
最近在学习fabric 2.1 版本源码,其中在endorserSupportImpl 结构中使用了Go的plugin 技术。所以这里准备记录下Go Plugin 是什么,怎么用。这里部分参考了https://www.jianshu.com/p/4ab799081a99 的介绍(特记录并表示感谢)
什么是Go PluginGolang是静态编译型语言,在编译时就将所有引用的包(库)全部加载打包到最终的可执行程序(或库文件)中,因此并不能在运行时动态加载其他共享库。Go Plugin提供了这样一种方式,能够让你在运行时动态加载外部功能。
fabric为什么用Go Plugin其实应该问为什么要用Plugin,我觉得原因有很多,比如:
- 可插拔:有了Plugin,我的程序可以根据需要随时替换其中某些部件而不用修改我的程序;
- 动态加载的需要:有些模块只有在运行时才能确定,需要动态加载外部的功能模块;
- 独立开发:Plugin 可以和主程序独立建设,主程序只需要制定好框架,实现默认(模版)功能。Plugin 可根据用户需求随时自行扩展开发,运行时随意替换,提高了程序的可定制性;
plugin
type Plugin struct{ ... }
func Open(path string) (*Plugin, error)
func (p *Plugin) Lookup(symName string) (Symbol, error)
type Symbol interface{}
我们可以发现只有两个方法还是很简单的。
Plugin
Plugin
Openpath*GluginLookup*PluginsymNameSymbol
示例:
pluginhello worldpluginhello.go
package main
import (
"fmt"
)
// plugin 源码必须在main 包中
func Hello() {
fmt.Println("Hello World From Plugin!")
}
HelloHello World From Plugin!
编译为可执行程序:
go build --buildmode=plugin -o pluginhello.so pluginhello.go
go buildbuildmodeplugin
调用示例:
package main
import (
"fmt"
"os"
"plugin"
)
func main() {
p, err := plugin.Open("./pluginhello.so")
if err != nil {
fmt.Println("error open plugin: ", err)
os.Exit(-1)
}
s, err := p.Lookup("Hello")
if err != nil {
fmt.Println("error lookup Hello: ", err)
os.Exit(-1)
}
if hello, ok := s.(func()); ok {
hello()
}
}
OpenHellofunc HelloSymbolinterface{}
go run invokeplugin.go
//打印
Hello World From Plugin!
成功!!!