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
    
  • 相关阅读:
    maven学习(十六)——使用Maven构建多模块项目
    jsp页面提示“Multiple annotations found at this line:
    SQL中Truncate语法
    java时间工具类,时间相互转换
    Date转换为LocalDateTime
    新建的maven项目里没有src
    maven-version
    spring-boot-configuration-processor
    python爬取文件时,内容为空
    IntelliJ IDEA 创建的文件自动生成 Author 注释 签名
  • 原文地址:https://www.cnblogs.com/baizx/p/9786045.html
Copyright © 2011-2022 走看看