插件化開發提供了很多便利,可動態擴展程序的相關功能,如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 參數,禁止優化、禁止內聯,則主程序調用插件時也必須加上;