分享
  1. 首页
  2. 文章

一个golang项目笔记 (二) 动态加载库

elonlee · · 3908 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

这个项目需要用到动态链接库技术, 主程序动态加载一些功能模块,这样在扩充功能时,无须修改主程序,只需要新增功能模块动态调用就可以了。 研究了一下golang官方支持的plugin功能,发现有几点不足。

1.官方plugin功能本质上是用cgo实现的,编译一个so文件,然后再调用

2. 只支持linux, 不支持windows

3. plugin模块panic时, 主程序也会panic, 无法做到隔离。

基于上述原因,我开始另外寻找合适的第三方支持。后来发现这样一个开源库,https://github.com/hashicorp/go-plugin , 感觉符合我的需求。它基于net/rpc ,grpc实现,主程序和plugin程序是两个qtj独立进程,可以通过主程序调用plugin进程启动,也可以附加进程的方式。通过本地网络通讯,达到类似动态链接库调用的效果。

官方示例如下:

plugin:

package main
import (
	"os"
	"github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/go-plugin/examples/basic/commons"
)
// Here is a real implementation of Greeter
type GreeterHello struct {
	logger hclog.Logger
}
func (g *GreeterHello) Greet() string {
	g.logger.Debug("message from GreeterHello.Greet")
	return "Hello!"
}
// handshakeConfigs are used to just do a basic handshake between
// a plugin and host. If the handshake fails, a user friendly error is shown.
// This prevents users from executing bad plugins or executing a plugin
// directory. It is a UX feature, not a security feature.
var handshakeConfig = plugin.HandshakeConfig{
	ProtocolVersion: 1,
	MagicCookieKey: "BASIC_PLUGIN",
	MagicCookieValue: "hello",
}
func main() {
	logger := hclog.New(&hclog.LoggerOptions{
		Level: hclog.Trace,
		Output: os.Stderr,
		JSONFormat: true,
	})
	greeter := &GreeterHello{
		logger: logger,
	}
	// pluginMap is the map of plugins we can dispense.
	var pluginMap = map[string]plugin.Plugin{
		"greeter": &example.GreeterPlugin{Impl: greeter},
	}
	logger.Debug("message from plugin", "foo", "bar")
	plugin.Serve(&plugin.ServeConfig{
		HandshakeConfig: handshakeConfig,
		Plugins: pluginMap,
	})
}

主程序 (调用方):

package main
import (
	"fmt"
	"log"
	"os"
	"os/exec"
	hclog "github.com/hashicorp/go-hclog"
	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/go-plugin/examples/basic/commons"
)
func main() {
	// Create an hclog.Logger
	logger := hclog.New(&hclog.LoggerOptions{
		Name: "plugin",
		Output: os.Stdout,
		Level: hclog.Debug,
	})
	// We're a host! Start by launching the plugin process.
	client := plugin.NewClient(&plugin.ClientConfig{
		HandshakeConfig: handshakeConfig,
		Plugins: pluginMap,
		Cmd: exec.Command("./plugin/greeter"),
		Logger: logger,
	})
	defer client.Kill()
	// Connect via RPC
	rpcClient, err := client.Client()
	if err != nil {
		log.Fatal(err)
	}
	// Request the plugin
	raw, err := rpcClient.Dispense("greeter")
	if err != nil {
		log.Fatal(err)
	}
	// We should have a Greeter now! This feels like a normal interface
	// implementation but is in fact over an RPC connection.
	greeter := raw.(example.Greeter)
	fmt.Println(greeter.Greet())
}
// handshakeConfigs are used to just do a basic handshake between
// a plugin and host. If the handshake fails, a user friendly error is shown.
// This prevents users from executing bad plugins or executing a plugin
// directory. It is a UX feature, not a security feature.
var handshakeConfig = plugin.HandshakeConfig{
	ProtocolVersion: 1,
	MagicCookieKey: "BASIC_PLUGIN",
	MagicCookieValue: "hello",
}
// pluginMap is the map of plugins we can dispense.
var pluginMap = map[string]plugin.Plugin{
	"greeter": &example.GreeterPlugin{},
}

有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:elonlee

查看原文:一个golang项目笔记 (二) 动态加载库

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
3908 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏