Go 插件功能的實現方式
官方實現
golang 1.8 及以上版本提供了一個創建共享庫(shared object)的新工具,稱爲 Plugins。目前 Plugins 僅在 Linux、FreeBSD 和 macOS 上受支持,且只支持 golang 調用。
使用示例,定義一個 plugin.go
:
package main
import (
"log"
)
func init() {
log.Println("plugin init")
}
type SayHello struct {
}
func (s *SayHello) CallMe(name string) string {
log.Println("hello ", name)
return "I am plugin"
}
// SayHelloPlugin 導出變量
var SayHelloPlugin SayHello
使用 -buildmode=plugin
模式編譯出 plugin.so
共享庫
go build -o plugin.so -buildmode=plugin plugin.go
main.go
中調用插件:
package main
import (
"log"
"plugin"
)
type CustomPlugin interface {
CallMe(name string) string
}
func main() {
// 打開插件(併發安全)
p, err := plugin.Open("plugin.so")
if err != nil {
panic(err)
}
// 在插件中搜索可導出的變量或函數
sayHelloPlugin, err := p.Lookup("SayHelloPlugin")
if err != nil {
panic(err)
}
// 斷言插件類型
if sayHello, ok := sayHelloPlugin.(CustomPlugin); ok {
log.Println(sayHello.CallMe("togettoyou"))
}
}
go run main.go
# 輸出
2021/07/28 17:07:21 plugin init
2021/07/28 17:07:21 hello togettoyou
2021/07/28 17:07:21 I am plugin
定義一個插件總結:
-
package 包名需要定義爲 main
-
必須有可導出的變量或函數
-
不需要 main 函數
-
插件加載時會先執行 init 函數
Traefik Yaegi 實現
Yaegi 是 Traefik 開源的 Go 解釋器。Traefik 自身的插件實現就是使用的 Yaegi 。
Yaegi 運行在 Go 運行時之上,可以直接作爲嵌入式解釋器,或使用交互式 shell ,解釋運行 Go 代碼。不過只支持 Go 1.15 和 Go 1.16(最新的 2 個主要版本)。
創建代碼目錄結構如下:
│ go.mod
│ go.sum
│ main.go
│
└─plugin
└─src
└─hello
go.mod
hello.go
這裏有個注意點,Yaegi 的插件需要放在 src 目錄下。
其中 hello.go
代碼:
package hello
import (
"fmt"
)
func init() {
fmt.Println("hello plugin init")
}
func CallMe(msg string) string {
fmt.Println(msg)
return "I am plugin"
}
main.go
代碼:
package main
import (
"fmt"
"github.com/traefik/yaegi/interp"
"github.com/traefik/yaegi/stdlib"
)
func main() {
// 初始化解釋器
i := interp.New(interp.Options{GoPath: "./plugin/"})
// 插件需要使用標準庫
if err := i.Use(stdlib.Symbols); err != nil {
panic(err)
}
// 導入 hello 包
if _, err := i.Eval(`import "hello"`); err != nil {
panic(err)
}
// 調用 hello.CallMe
v, err := i.Eval("hello.CallMe")
if err != nil {
panic(err)
}
callMe := v.Interface().(func(string) string)
fmt.Println(callMe("togettoyou"))
}
go run main.go
# 輸出
hello plugin init
togettoyou
I am plugin
我爲大家整理了一份從入門到進階的 Go 學習資料禮包,包含學習建議:入門看什麼,進階看什麼。關注公衆號 「polarisxu」,回覆 ebook 獲取;還可以回覆「進羣」,和數萬 Gopher 交流學習。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/EbG4RVd7jsoD3YmiP6Az8w