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


    这个项目需要用到动态链接库技术, 主程序动态加载一些功能模块,这样在扩充功能时,无须修改主程序,只需要新增功能模块动态调用就可以了。 研究了一下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{},
    }
    

      

  • 相关阅读:
    模板
    常用文件的位置
    前端基础之JavaScript
    CSS属性相关
    前端之CSS
    jQuery方法及使用
    前端-HTLM
    前端之BOM与DOM-JQuery
    视图-触发器-事务-存储过程-函数
    Navicat-pymysql-sql注入问题
  • 原文地址:https://www.cnblogs.com/elonlee/p/9499684.html
Copyright © 2020-2023  润新知