zoukankan      html  css  js  c++  java
  • golang plugin的依赖问题

    golang plugin的依赖问题

    此文中涉及的plugin运行环境为mac 10.14,go版本为1.11
    主要是想讨论一下插件依赖的第三方库的问题.
    例子是在https://github.com/vladimirvivien/go-plugin-example一文基础之上.

    简单插件

    1.主程序

    package main
    
    import (
    	"fmt"
    	"os"
    	"plugin"
    )
    
    type Greeter interface {
    	Greet()
    }
    
    func main() {
    	// load module
    	// 1. open the so file to load the symbols
    	plug, err := plugin.Open("./eng/eng.so")
    	if err != nil {
    		fmt.Println(err)
    		os.Exit(1)
    	}
    
    	// 2. look up a symbol (an exported function or variable)
    	// in this case, variable Greeter
    	symGreeter, err := plug.Lookup("Greeter")
    	if err != nil {
    		fmt.Println(err)
    		os.Exit(1)
    	}
    
    	// 3. Assert that loaded symbol is of a desired type
    	// in this case interface type Greeter (defined above)
    	var greeter Greeter
    	greeter, ok := symGreeter.(Greeter)
    	if !ok {
    		fmt.Println("unexpected type from module symbol")
    		os.Exit(1)
    	}
    
    	// 4. use the module
    	greeter.Greet()
    
    }
    

    2. plugin代码

    package main
    
    import "fmt"
    
    type greeting string
    
    func (g greeting) Greet() {
    	fmt.Println("Hello Universe")
    }
    
    // exported
    var Greeter greeting
    

    3. plugin编译方法

    go build -buildmode=plugin -o eng/eng.so eng/greeter.go
    

    4. 运行结果

    go run main.go
    Hello Universe
    

    插件与主程序依赖第三方库的问题

    如果主程序和插件都依赖第三方库会有什么问题呢?他们是共享一份代码?还是完全独立的copy呢?
    这就类似于c语言动态链接库的依赖,但是应该又不一样. 以实验结果说话吧.

    1. 同时依赖的第三方库

    package anotherlib
    var ShareVariable =7
    

    2. 运行结果

    和平时常见的动态库行为一致,也就是说主程序和插件共享了一份运行代码,也共享了一份运行变量.

    引入了vendor的问题

    实际项目中,可能代码都会使用vendor来管理自己的第三方依赖库.
    这时候就会出现不一致的情况.也就是说因为主程序使用了vendor或者插件使用了vendor,
    那么这时候go runtime就会认为插件和主程序用的不是同一个第三方依赖库,这时候就会出现和预期不一致的情况.

    完整的代码

    我已经把代码放在github,刚兴趣可以下载运行,

    main.go

    package main
    
    import (
    	"fmt"
    	"os"
    	"plugin"
    	"github.com/nkbai/blog/goplugin/anotherlib"
    )
    
    type Greeter interface {
    	Greet()
    	GetShareVariable() int
    }
    
    func main() {
    	// load module
    	// 1. open the so file to load the symbols
    	plug, err := plugin.Open("./eng/eng.so")
    	if err != nil {
    		fmt.Println(err)
    		os.Exit(1)
    	}
    
    	// 2. look up a symbol (an exported function or variable)
    	// in this case, variable Greeter
    	symGreeter, err := plug.Lookup("Greeter")
    	if err != nil {
    		fmt.Println(err)
    		os.Exit(1)
    	}
    
    	// 3. Assert that loaded symbol is of a desired type
    	// in this case interface type Greeter (defined above)
    	var greeter Greeter
    	greeter, ok := symGreeter.(Greeter)
    	if !ok {
    		fmt.Println("unexpected type from module symbol")
    		os.Exit(1)
    	}
    
    	// 4. use the module
    	greeter.Greet()
    
    	fmt.Println("anotherlib in main")
    	fmt.Println(anotherlib.ShareVariable)
    	fmt.Printf("plugin anotherlib =%d
    ",greeter.GetShareVariable())
    	fmt.Println("change anotherlib's variable")
    	anotherlib.ShareVariable=5
    	fmt.Printf("main share=%d,plugin share=%d
    ",anotherlib.ShareVariable,greeter.GetShareVariable())
    	//可以看到输出都是5
    
    	//下面这种情况将会出现不一致的情况
    	testpluginvendor()
    }
    
    func testpluginvendor(){
    		// load module
    	// 1. open the so file to load the symbols
    	plug, err := plugin.Open("pluginwithvendor/eng.so")
    	if err != nil {
    		fmt.Println(err)
    		os.Exit(1)
    	}
    
    	// 2. look up a symbol (an exported function or variable)
    	// in this case, variable Greeter
    	symGreeter, err := plug.Lookup("Greeter")
    	if err != nil {
    		fmt.Println(err)
    		os.Exit(1)
    	}
    
    	// 3. Assert that loaded symbol is of a desired type
    	// in this case interface type Greeter (defined above)
    	var greeter Greeter
    	greeter, ok := symGreeter.(Greeter)
    	if !ok {
    		fmt.Println("unexpected type from module symbol")
    		os.Exit(1)
    	}
    
    	// 4. use the module
    	greeter.Greet()
    	fmt.Println("call plugin withvendor")
    	fmt.Println("anotherlib in main")
    	fmt.Println(anotherlib.ShareVariable)
    	fmt.Printf("plugin anotherlib =%d
    ",greeter.GetShareVariable())
    	fmt.Println("change anotherlib's variable")
    	anotherlib.ShareVariable=5
    	fmt.Printf("main share=%d,plugin share=%d
    ",anotherlib.ShareVariable,greeter.GetShareVariable())
    	//可以看到输出并不一致
    }
    

    plugin eng.go

    package main
    
    import "fmt"
    import "github.com/nkbai/blog/goplugin/anotherlib"
    
    type greeting string
    
    func (g greeting) Greet() {
    	fmt.Println("Hello Universe")
    }
    func (g greeting) GetShareVariable() int{
    	return anotherlib.ShareVariable
    }
    // exported
    var Greeter greeting
    

    第三方依赖库 anotherlib.go

    package anotherlib
    var ShareVariable =7
    
  • 相关阅读:
    sqlserver 执行脚本报内存溢出的处理方式
    框架重构:测试中的DateTime.Now
    框架重构:规范集成测试的结构和命名规则
    框架重构:记录创建人、最后修改人、创建时间、最后修改时间
    从VS2010跳跃到VS2017
    ASP.NET网站发布时的那些坑
    使用pjax时点击浏览器刷新按钮仅加载内容页的解决办法
    让ASP.NET第一次请求不变慢
    正确设置Firefox下载文件文件名的方法
    通过反编译让SpecFlow支持多层属性值的验证
  • 原文地址:https://www.cnblogs.com/baizx/p/9786045.html
Copyright © 2011-2022 走看看