Go Plugins插件的实现方式

作者:togettoyou 时间:2023-10-15 01:51:20 

官方实现

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

来源:https://www.cnblogs.com/togettoyou/p/goplugins.html

标签:Go,Plugins,插件
0
投稿

猜你喜欢

  • ASP JSON类源码

    2011-04-30 16:38:00
  • jRaiser与jQuery的冲突问题

    2010-07-27 12:36:00
  • Oracle常用dump命令,记录一下备查。

    2009-03-04 10:27:00
  • 关于window.opener的用法

    2008-02-23 11:03:00
  • python安装pillow的三种方法

    2023-07-20 02:36:53
  • Asp无组件生成缩略图

    2007-10-26 12:08:00
  • 数据仓库基本报表制作过程中的SQL写法

    2008-11-25 12:17:00
  • Web 2.0 框架发布

    2008-03-25 09:40:00
  • 内联格式化模式(line-height原理)

    2008-06-29 14:37:00
  • MySQL的双机热备份安装和配置

    2012-01-05 19:00:58
  • Pytorch中DataLoader的使用方法详解

    2023-07-19 04:45:39
  • 详解如何用Python模拟登录淘宝

    2023-09-29 19:07:34
  • 如何利用python写GUI及生成.exe可执行文件

    2023-06-26 00:42:57
  • 最新google pr查询接口

    2012-03-12 20:00:39
  • Oracle 异构服务实践

    2007-08-17 10:00:00
  • MySQL鲜为人知的几个特殊技巧

    2009-03-09 13:22:00
  • 按键标示的设计体验

    2008-08-27 12:06:00
  • Javascript学习第一季 三

    2008-06-27 13:08:00
  • 实例:arguments.callee的应用

    2009-04-20 12:38:00
  • Oracle密码文件的使用和维护第1/3页

    2010-07-30 12:43:00
  • asp之家 网络编程 m.aspxhome.com