golang plugin的依赖问题

此文中涉及的plugin运行环境为mac 10.14,go版本为1.11

主要是想讨论一下插件依赖的第三方库的问题.

例子是在https://github.com/vladimirvivien/go-plugin-example一文基础之上.

简单插件

1.主程序

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "plugin"
  6. )
  7. type Greeter interface {
  8. Greet()
  9. }
  10. func main() {
  11. // load module
  12. // 1. open the so file to load the symbols
  13. plug, err := plugin.Open("./eng/eng.so")
  14. if err != nil {
  15. fmt.Println(err)
  16. os.Exit(1)
  17. }
  18. // 2. look up a symbol (an exported function or variable)
  19. // in this case, variable Greeter
  20. symGreeter, err := plug.Lookup("Greeter")
  21. if err != nil {
  22. fmt.Println(err)
  23. os.Exit(1)
  24. }
  25. // 3. Assert that loaded symbol is of a desired type
  26. // in this case interface type Greeter (defined above)
  27. var greeter Greeter
  28. greeter, ok := symGreeter.(Greeter)
  29. if !ok {
  30. fmt.Println("unexpected type from module symbol")
  31. os.Exit(1)
  32. }
  33. // 4. use the module
  34. greeter.Greet()
  35. }

2. plugin代码

  1. package main
  2. import "fmt"
  3. type greeting string
  4. func (g greeting) Greet() {
  5. fmt.Println("Hello Universe")
  6. }
  7. // exported
  8. var Greeter greeting

3. plugin编译方法

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

4. 运行结果

  1. go run main.go
  2. Hello Universe

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

如果主程序和插件都依赖第三方库会有什么问题呢?他们是共享一份代码?还是完全独立的copy呢?

这就类似于c语言动态链接库的依赖,但是应该又不一样. 以实验结果说话吧.

1. 同时依赖的第三方库

  1. package anotherlib
  2. var ShareVariable =7

2. 运行结果

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

引入了vendor的问题

实际项目中,可能代码都会使用vendor来管理自己的第三方依赖库.

这时候就会出现不一致的情况.也就是说因为主程序使用了vendor或者插件使用了vendor,

那么这时候go runtime就会认为插件和主程序用的不是同一个第三方依赖库,这时候就会出现和预期不一致的情况.

完整的代码

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

main.go

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "plugin"
  6. "github.com/nkbai/blog/goplugin/anotherlib"
  7. )
  8. type Greeter interface {
  9. Greet()
  10. GetShareVariable() int
  11. }
  12. func main() {
  13. // load module
  14. // 1. open the so file to load the symbols
  15. plug, err := plugin.Open("./eng/eng.so")
  16. if err != nil {
  17. fmt.Println(err)
  18. os.Exit(1)
  19. }
  20. // 2. look up a symbol (an exported function or variable)
  21. // in this case, variable Greeter
  22. symGreeter, err := plug.Lookup("Greeter")
  23. if err != nil {
  24. fmt.Println(err)
  25. os.Exit(1)
  26. }
  27. // 3. Assert that loaded symbol is of a desired type
  28. // in this case interface type Greeter (defined above)
  29. var greeter Greeter
  30. greeter, ok := symGreeter.(Greeter)
  31. if !ok {
  32. fmt.Println("unexpected type from module symbol")
  33. os.Exit(1)
  34. }
  35. // 4. use the module
  36. greeter.Greet()
  37. fmt.Println("anotherlib in main")
  38. fmt.Println(anotherlib.ShareVariable)
  39. fmt.Printf("plugin anotherlib =%d\n",greeter.GetShareVariable())
  40. fmt.Println("change anotherlib's variable")
  41. anotherlib.ShareVariable=5
  42. fmt.Printf("main share=%d,plugin share=%d\n",anotherlib.ShareVariable,greeter.GetShareVariable())
  43. //可以看到输出都是5
  44. //下面这种情况将会出现不一致的情况
  45. testpluginvendor()
  46. }
  47. func testpluginvendor(){
  48. // load module
  49. // 1. open the so file to load the symbols
  50. plug, err := plugin.Open("pluginwithvendor/eng.so")
  51. if err != nil {
  52. fmt.Println(err)
  53. os.Exit(1)
  54. }
  55. // 2. look up a symbol (an exported function or variable)
  56. // in this case, variable Greeter
  57. symGreeter, err := plug.Lookup("Greeter")
  58. if err != nil {
  59. fmt.Println(err)
  60. os.Exit(1)
  61. }
  62. // 3. Assert that loaded symbol is of a desired type
  63. // in this case interface type Greeter (defined above)
  64. var greeter Greeter
  65. greeter, ok := symGreeter.(Greeter)
  66. if !ok {
  67. fmt.Println("unexpected type from module symbol")
  68. os.Exit(1)
  69. }
  70. // 4. use the module
  71. greeter.Greet()
  72. fmt.Println("call plugin withvendor")
  73. fmt.Println("anotherlib in main")
  74. fmt.Println(anotherlib.ShareVariable)
  75. fmt.Printf("plugin anotherlib =%d\n",greeter.GetShareVariable())
  76. fmt.Println("change anotherlib's variable")
  77. anotherlib.ShareVariable=5
  78. fmt.Printf("main share=%d,plugin share=%d\n",anotherlib.ShareVariable,greeter.GetShareVariable())
  79. //可以看到输出并不一致
  80. }

plugin eng.go

  1. package main
  2. import "fmt"
  3. import "github.com/nkbai/blog/goplugin/anotherlib"
  4. type greeting string
  5. func (g greeting) Greet() {
  6. fmt.Println("Hello Universe")
  7. }
  8. func (g greeting) GetShareVariable() int{
  9. return anotherlib.ShareVariable
  10. }
  11. // exported
  12. var Greeter greeting

第三方依赖库 anotherlib.go

  1. package anotherlib
  2. var ShareVariable =7

golang plugin的依赖问题的更多相关文章

  1. Sublime+Golang Plugin

    很喜欢在Sublime开发Golang程序,主要是要一个Sublime Golang Plugin, 可以给代码autocomplement.相当的棒! 1.安装Sublime https://www ...

  2. 使用Maven Assembly plugin将依赖打包进jar

    一个Eclipse的工程,在pom中配置了若干依赖,需要将pom中所有的依赖全部打包进一个jar包中,可以选择的方案有maven-assembly-plugin和fatjar.以前采用fatjar进行 ...

  3. Golang modules包依赖管理工具

    初始化 执行go mod  init module-name,其中module-name为包名字,执行完后会生成go.mod文件,如下 module module-name go 1.13 包管理 使 ...

  4. install golang plugin in webstrom

    https://github.com/go-lang-plugin-org/go-lang-idea-plugin/wiki/Documentation

  5. Golang 无法下载依赖 golang.org (GoLand解决方法)

    如下图所示将Proxy设置为:https://goproxy.io/

  6. 解决vscode中golang插件依赖安装失败问题

    vscode中安装ms-vscode.go插件后可以开启对go语言的支持,ms-vscode.go插件需要依赖一些工具,安装完成后提示 gocode go-outline go-symbols gur ...

  7. maven工程打包成runnable的jar包,拷贝资源和依赖jar包

    eclipse下新建maven工程,生成runnable的jar包.之前一直是手动拷贝依赖的jar包和资源文件,烦得要死.上网可劲查了一下.解决方案如下. 在pom的配置文件中做如下配置: <b ...

  8. [golang学习] 在idea中code & debug

    [已废弃]不需要看 idea 虽然审美倒退了n年. 不过功能还是相当好用的. idea 的go插件堪称最好的go ide. 1. 语法高亮支持 2. 智能提示 3. 跳转定义(反跳转回来) 4. 集成 ...

  9. 基于Maven管理的Mapreduce程序下载依赖包到LIB目录

    1.Mapreduce程序需要打包作为作业提交到Hadoop集群环境运行,但是程序中有相关的依赖包,如果没有一起打包,会出现xxxxClass Not Found . 2.在pom.xml文件< ...

随机推荐

  1. ES6系列_9之对象

    1.对象赋值 es5中的对象赋值方式如下: let name="小明"; let skill= 'es6开发'; var obj= {name:name,skill:skill}; ...

  2. leetcode116

    class Solution { public: void connect(TreeLinkNode *root) { if (root != NULL) { queue<TreeLinkNod ...

  3. Spring cloud 分布式锁

    https://github.com/easonstudy/springboot_demo study目录中

  4. zk分布式锁-排它锁简单实现

    package Lock; import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import ...

  5. 关于ErrorPage

    JSP里创建一个网页test.jsp, 让这个网页上面出现一个错误, 再创建一个切换页面error.jsp, 使test.jsp如果出现错误就切换到error.jsp上, 但是怎么试都是出现一个网页上 ...

  6. freemaker在表格中遍历数据

    Controller层如下所示: @RequestMapping(value = "/test", method = RequestMethod.GET) public Strin ...

  7. 命令--cut

    --按文件大小排序 显示前100行 显示后五列 ll -Sh|head -n 100|cut -d ' ' -f 5- 一.基本语法cut是一个选取命令,以行为单位,用指定分隔符将行切分为若干字段,选 ...

  8. 1-为什么java的main方法必须是静态的

    为什么java的main方法必须是静态的   今天看类型信息时发现一个问题,不能再main方法中打印this关键字的信息,这时想起了之前的知识,不能再静态方法中调用this.理由很简单,this表示“ ...

  9. Introduction Sockets to Programming in C using TCP/IP

    Introduction Computer Network: hosts, routers, communication channels Hosts run applications Routers ...

  10. 不同包之间的继承extends

    情景如下: 两个类:ExtendsSuper(父类).ExtendsSub(子类) 两个包:父类ExtendsSuper位于包packSuper路径下,子类ExtendsSub位于包packSub路径 ...