Go Plugins插件的實(shí)現(xiàn)方式
官方實(shí)現(xiàn)
golang 1.8 及以上版本提供了一個(gè)創(chuàng)建共享庫(kù)(shared object)的新工具,稱為 Plugins。目前 Plugins 僅在 Linux、FreeBSD 和 macOS 上受支持,且只支持 golang 調(diào)用。
使用示例,定義一個(gè) 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 導(dǎo)出變量 var SayHelloPlugin SayHello
使用 -buildmode=plugin
模式編譯出 plugin.so
共享庫(kù)
go build -o plugin.so -buildmode=plugin plugin.go
main.go
中調(diào)用插件:
package main import ( "log" "plugin" ) type CustomPlugin interface { CallMe(name string) string } func main() { // 打開(kāi)插件(并發(fā)安全) p, err := plugin.Open("plugin.so") if err != nil { panic(err) } // 在插件中搜索可導(dǎo)出的變量或函數(shù) 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
定義一個(gè)插件總結(jié):
- package 包名需要定義為 main
- 必須有可導(dǎo)出的變量或函數(shù)
- 不需要 main 函數(shù)
- 插件加載時(shí)會(huì)先執(zhí)行 init 函數(shù)
Traefik Yaegi 實(shí)現(xiàn)
Yaegi 是 Traefik 開(kāi)源的 Go 解釋器。Traefik 自身的插件實(shí)現(xiàn)就是使用的 Yaegi 。
Yaegi 運(yùn)行在 Go 運(yùn)行時(shí)之上,可以直接作為嵌入式解釋器,或使用交互式 shell ,解釋運(yùn)行 Go 代碼。不過(guò)只支持 Go 1.15 和 Go 1.16(最新的 2 個(gè)主要版本)。
創(chuàng)建代碼目錄結(jié)構(gòu)如下:
│ go.mod │ go.sum │ main.go │ └─plugin └─src └─hello go.mod hello.go
這里有個(gè)注意點(diǎn),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/"}) // 插件需要使用標(biāo)準(zhǔn)庫(kù) if err := i.Use(stdlib.Symbols); err != nil { panic(err) } // 導(dǎo)入 hello 包 if _, err := i.Eval(`import "hello"`); err != nil { panic(err) } // 調(diào)用 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
到此這篇關(guān)于Go Plugins插件的實(shí)現(xiàn)方式的文章就介紹到這了,更多相關(guān)Go Plugins插件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
談?wù)剬?duì)Golang IO讀寫(xiě)的困惑
這篇文章主要介紹了談?wù)剬?duì)Golang IO讀寫(xiě)的困惑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08golang 如何實(shí)現(xiàn)HTTP代理和反向代理
這篇文章主要介紹了golang 實(shí)現(xiàn)HTTP代理和反向代理的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05go goroutine 怎樣進(jìn)行錯(cuò)誤處理
在 Go 語(yǔ)言程序開(kāi)發(fā)中,goroutine 的使用是比較頻繁的,因此在日常編碼的時(shí)候 goroutine 里的錯(cuò)誤處理,怎么做會(huì)比較好呢,本文就來(lái)詳細(xì)介紹一下2021-07-07golang DNS服務(wù)器的簡(jiǎn)單實(shí)現(xiàn)操作
這篇文章主要介紹了golang DNS服務(wù)器的簡(jiǎn)單實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04