Go Plugins插件的实现方式

 更新时间:2021年08月06日 11:48:09   作者:togettoyou  
目前 Plugins 仅在 Linux、FreeBSD 和 macOS 上受支持,且只支持 golang 调用,今天通过本文给大家介绍Go Plugins插件的实现方式,感兴趣的朋友一起看看吧

官方实现

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插件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 谈谈对Golang IO读写的困惑

    谈谈对Golang IO读写的困惑

    这篇文章主要介绍了谈谈对Golang IO读写的困惑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • 特殊字符的json序列化总结大全

    特殊字符的json序列化总结大全

    这篇文章主要给大家介绍了关于特殊字符的json序列化的相关资料,通过示例代码分别给大家介绍了关于python 、 rust 、 java 和golang对特殊字符的json序列化操作,需要的朋友可以参考借鉴,下面来一起学习学习吧
    2018-09-09
  • 深入了解Golang官方container/heap用法

    深入了解Golang官方container/heap用法

    在 Golang 的标准库 container 中,包含了几种常见的数据结构的实现,其实是非常好的学习材料。今天我们就来看看 container/heap 的源码,了解一下官方的同学是怎么设计,我们作为开发者又该如何使用
    2022-10-10
  • 详解Golang中下划线的使用方法

    详解Golang中下划线的使用方法

    这篇文章主要介绍了详解Golang中下划线的使用方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • golang 如何实现HTTP代理和反向代理

    golang 如何实现HTTP代理和反向代理

    这篇文章主要介绍了golang 实现HTTP代理和反向代理的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • go goroutine 怎样进行错误处理

    go goroutine 怎样进行错误处理

    在 Go 语言程序开发中,goroutine 的使用是比较频繁的,因此在日常编码的时候 goroutine 里的错误处理,怎么做会比较好呢,本文就来详细介绍一下
    2021-07-07
  • 基于go微服务效率工具goctl深度解析

    基于go微服务效率工具goctl深度解析

    这篇文章主要为大家介绍了基于go微服务效率工具goctl深度解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • 详解Golang使用MongoDB通用操作

    详解Golang使用MongoDB通用操作

    这篇文章主要介绍了详解Golang使用MongoDB通用操作,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • 深入Golang之context的用法详解

    深入Golang之context的用法详解

    本篇文章主要介绍了深入Golang之context的用法详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • golang DNS服务器的简单实现操作

    golang DNS服务器的简单实现操作

    这篇文章主要介绍了golang DNS服务器的简单实现操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论