golang依赖包初始化
#前言
还是没想好日常的记录应该以什么形式表达,感觉以月或以周太过零散,不方便汇总和查找,以太大的主题包裹又无法快速回顾这段时间做了什么。或许冗余是一个不错的选择。
日常开发接入 ab 实验中间件,由于逻辑未生效,所以尝试去通过文档找寻原因,其中一段文档明确点名xx变量的初始化一定要在全局Init(nil)之前执行
,突然产生疑问:诶?以前好像没有特意保证过这点,之前又是怎么生效的呢?
带着疑问顺便把 golang 的依赖包初始化整体看了一下,并记录。
#测试
首先在 Init(nil)函数之前打断点,在初始化变量的位置新增 init()函数,打印一行日志。
在运行时,确定命令行有相关日志输出
,代表确实是先执行的变量初始化,再执行的 Init(nil)。
#规则
查阅资料:
基本原则是:
- 所有依赖的代码包是串行执行加载的,当一个包的所有依赖的包都加载完成后,才开始加载自身。
- 每个包只会被加载一次。
一些注意点:
- 包的初始化白皮书说按照 import path 的排序进行加载。
- 包内的初始化推荐按照文件名排序进行初始化。
- 包内的初始化,先初始化变量,再执行 init()函数。
- 有依赖的变量,如 a 的初始化依赖 b,先初始化 b 再初始化 a。
- 一个包内的 init()函数之间最好不要互相依赖。
也就是说,假设运行包为 A,依赖 B(外部依赖,如 ab 组件),依赖 C(定义 ab 组件的变量,依赖 B),依赖 D(内部实现代码,肯定依赖了 B,也在代码中依赖了 C 中的相关变量),那么:
由于 A 依赖其它,所以在 A 的执行代码 Init(nil)一定晚于 C 中关于 ab 组件的变量的初始化,符合组件要求。
基于逻辑上讲,C 的变量初始化一定是对 B 的全局内部变量进行了修改,而由于 C 依赖 B,所以 B 的内部变量定义也在 C 之前,所以是没有问题的。
#其它
之前还会思考,为什么有些中间件需要显式地在执行函数中运行 Init()函数,而且大部分 Init()函数都不需要传入任何配置,依赖的初始化顺序,是其中一个原因。
Be the first person to leave a comment!