欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Go Plugins插件的实现方式

程序员文章站 2022-03-04 15:05:27
官方实现golang 1.8 及以上版本提供了一个创建共享库(shared object)的新工具,称为 plugins。目前 plugins 仅在 linux、freebsd 和 macos 上受支...

官方实现

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 plugins插件的实现方式的文章就介绍到这了,更多相关go plugins插件内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

相关标签: Go Plugins 插件