插件化开发提供了很多便利,可动态扩展程序的相关功能,如Windows中的DLL、Linux中的So文件、还有IDEA中的插件,应用范围不可谓不广;
  在Golang中提供了自己的插件机制,可使用其进行插件化开发;在Golang的plugin包中提供了加载插件、调用插件中函数的相关方法;

Golang中的插件机制使用非常简单;就只有这么三步:
  1、编写插件库相关代码,生成so文件;
  2、加载插件so文件;
  3、调用相关的函数或字段;
下面用一个简单例子来看看插件的基本使用:

一、定义插件

  这个插件非常简单,定义一个公开的字段V,一个公开的函数F。

package main
import “fmt”

var V int
func F(){
  fmt.Printf(“Hello Plugin: %d\n”,V)
}

二、生成插件so文件

  生成so文件也和之前编译普通的go文件一样只是多了个参数;
  go build -buildmode=plugin demo.go
  执行上诉命令后将生成一个名为:demo.so的插件库文件;

三、使用插件

  有了插件现在到了使用插件,使用插件也没啥难度,具体代码如下:

p,err := plugin.Open(“demo.so”)
if err!=nil{
   panic(err)
}
v,err := p.Lookup(“V”)  //调用插件中的V字段
if err!=nil{
   panic(err)
}
f,err :=p.Lookup(“F”)  //调用插件中的F函数
if err!=nil{
   panic(err)
}
*v.(*int) = 100         
f.(fun())()        //类型断言,f为一个无参无返回值的函数fun(),然后调用函数f

插件调用的输出结果为:Hello Plugin: 100  

插件使用:

插件与主程序使用的接口必须是同一个
  通常使用流程:
  1、定义依赖的包文件,包含相关的接口等;
  2、插件实现上述所定义的接口
  3、主程序应用依赖包,调用插件实现;

一、包接口

package lib
type Calculator interface {
  Add(int, int) int
  Sub(int, int) int
}

二、插件实现

package main
import (
 "demo/lib"
)
type Call struct {}
func (c *Call) Sub(a, b int) int {
 return a - b
}
func (c *Call) Add(a, b int) int {
 return a + b
}
func NewCal() lib.Calculator {
  return &Call{}
}

三、主程序引用包,调用插件的相关实现

package main
import (
  "demo/lib"
  "fmt"
  "plugin"
)
p, err := plugin.Open("plugin/operation_plugin.so")
if err != nil {
   panic(err)
}
cal,err:= p.Lookup("NewCal")
if err != nil {
  panic(err)
}
c:= cal.(func ()lib.Calculator)()
fmt.Println(c.Add(3,5))
fmt.Println(c.Sub(20,10))

注意事项:
  编译插件所使用的参数必须与编译主程序所使用参数一直,否则将可能出现如下异常信息:

panic: plugin.Open("plugin/operation_plugin"): plugin was built with a different version of package runtime/internal/sys

  如在编译插件库so文件时使用了-gcflags all=-N -l 参数,禁止优化、禁止内联,则主程序调用插件时也必须加上;