環境
系統: linux (別問爲什麼,因爲windows下golang不支持動態庫)
golang版本: 1.5 以上支持動態庫,1.8以上支持plugin
插件代碼
插件代碼跟普通的golang模塊代碼沒啥差別,主要是package必須是 main。下面是一段簡易的插件代碼
//testplugin.go
package main
import (
"fmt"
)
func init() {
fmt.Println("world")
//我們還可以做其他更高階的事情,比如 platform.RegisterPlugin({"func": Hello}) 之類的,向插件平臺自動註冊該插件的函數
}
func Hello() {
fmt.Println("hello")
}
init 函數的目的是在插件模塊加載的時候自動執行一些我們要做的事情,比如:自動將方法和類型註冊到插件平臺、輸出插件信息等等。
Hello 函數則是我們需要在調用方顯式查找的symbol
編譯命令
go build -buildmode=plugin testplugin.go
編譯完後我們可以看到當前目錄下有一個 testplugin.so 文件
我們也可以通過類似如下命令來生成不同版本的插件
go build -o testplugin_v1.so -buildmode=plugin testplugin.go
如果要想更好的控制插件的版本,想做更酷的事情,比如:熱更新插件。那麼可以採用自動註冊的方式,新版本的插件加載上來後,自動註冊插件版本號,插件平臺裏優先使用新版本的方法。
使用
使用方需要引入 plugin 這個包
//main.go
package main
import (
"plugin"
)
func main() {
p, err := plugin.Open("testplugin.so")
if err != nil {
panic(err)
}
f, err := p.Lookup("Hello")
if err != nil {
panic(err)
}
f.(func())()
}
輸出
$ go run main.go
world
hello
我們可以看到,我們只顯式調用了插件中的Hello方法,打印hello這個字符串,但是在調用Hello之前,已經輸出了world,這個正是插件init函數做的事情。
總結
golang支持插件使得golang程序的擴展性上升到另一個臺階,可以用來做更酷的事情,如:利用插件做服務的熱更新