浅析依赖注入框架的生命周期(以 InversifyJS 为例)
在上一篇介绍了 VSCode 的依赖注入设计,并且实现了一个简单的 IOC 框架。但是距离成为一个生产环境可用的框架还差的很远。
行业内已经有许多非常优秀的开源 IOC 框架,它们划分了更为清晰地模块来应对复杂情况下依赖注入运行的正确性。
这里我将以 InversifyJS 为例,分析它的生命周期设计,来弄清楚在一个优秀的 IOC 框架中,完成一次注入流程到底是什么样的。
InversifyJS 的生命周期
在激活 InversifyJS 后,框架通常会监听并经历五个阶段,分别是:
- Annotation 注释阶段
- Planning 规划阶段
- Middleware (optional) 中间件钩子
- Resolution 解析执行阶段
- Activation (optional) 激活钩子
本篇文章将着重介绍其中的三个必选阶段。旨在解释框架到底是如何规划模块实例化的先后顺序,以实现依赖注入能力的。
接下来的解析将围绕如下例子:
@injectable()class FooBar implements FooBarInterface {public foo : FooInterface;public bar : BarInterface;constructor(@inject("FooInterface") foo: FooInterface, @inject("BarInterface") bar: BarInterface) {this.foo = foo;this.bar = bar;}}const container = new Container();const foobar = container.get<FooBarInterface>("FooBarInterface");
Annotation 注释阶段
在此阶段中,框架将通过装饰器为所有接入框架的对象打上标记,以便规划阶段时进行管理。
在这个阶段中,最重要的 API 就是 injectable 。它使用 Reflect metadata,对 Class 构造函数中通过 inject API 注入的 property 进行标注,并挂在在了该类的 metadataKey 上。
function injectable() {return function(target: any) {if (Reflect.hasOwnMetadata(METADATA_KEY.PARAM_TYPES, target)) {throw new Error(ERRORS_MSGS.DUPLICATED_INJECTABLE_DECORATOR);}const types = Reflect.getMetadata(METADATA_KEY.DESIGN_PARAM_TYPES, target) || [];Reflect.defineMetadata(METADATA_KEY.PARAM_TYPES, types, target);return target;};
}
Planning 规划阶段
本阶段时该框架的核心阶段,它真正生成了在一个 Container 中,所有类模块的依赖关系树。因此,在 Container 类进行实例化时,规划阶段就开始了。
在实例化时,根据传入的 id 与 scope 可以确定该实例容器的作用域范围,生成一个 context,拥有对内左右模块的管理权。
class Context implements interfaces.Context {public id: number;public container: interfaces.Container;public plan: interfaces.Plan;public currentRequest: interfaces.Request;public constructor(container: interfaces.Container) {this.id = id(); // generate a unique idthis.container = container;}public addPlan(plan: interfaces.Plan) {this.plan = plan;}public setCurrentRequest(currentRequest: interfaces.Request) {this.currentRequest = currentRequest;}
}
我们可以注意到,这个 context 中包含一个空的 plan 对象,这是 planning 阶段的核心,该阶段就是为生成的容器规划好要执行的任务。
plan 对象中将包含一个 request 对象,request 是一个可递归的属性结构,它包含了要查找的 id 外,还需要 target 参数,即规定找到依赖实例后将引用赋值给哪个参数。
class Request implements interfaces.Request {public id: number;public serviceIdentifier: interfaces.ServiceIdentifier<any>; // 被修饰类 idpublic parentContext: interfaces.Context;public parentRequest: interfaces.Request | null; // 树形结构的 request,指向父节点public bindings: interfaces.Binding<any>[];public childRequests: interfaces.Request[]; // 树形结构的 request,指向子节点public target: interfaces.Target; // 指向赋值目标参数public requestScope: interfaces.RequestScope;...
}
以篇头的例子为例。在容器执行 get 函数后,框架生成了一个新的 plan,该 plan 的生成过程中将执行_createSubRequests 方法,从上而下创建 Request 依赖树。
创建完成后的 plan 对象生成的 request 树将包含有请求目标为 null 的根 request 与两个子 request:
第一个子 request 指向 FooInterface 接口,并且请求结果的 target 赋值给构造函数中的参数 foo。第二个子 request 指向 BarInterface 接口,并且请求结果的 target 赋值给构造函数中的参数 bar。
注意,此处的依赖树生成仍在 interface 层面,没有任何类被实例化。
用一张图来更直观地表现该阶段中各对象的生成调用过程:

这样,每一个类与其依赖项之间的请求关系就构造完毕了。
Resolution 解析执行阶段
该阶段便是执行在规划阶段中生成的 request 依赖树,从无依赖的叶子节点开始,自下而上实例化每一个依赖类,到根 request 结束时,即最终完成 FooBar 自身的实例化。
且该解析过程可以选择同步或异步执行,在复杂情况下,使用异步懒加载的方式执行解析,有助于提高性能。
至此,一次完整的具有依赖的类的实例化就完成了。我们可以通过打印依赖树,清晰地观察到该实例依赖了哪些实例,从而避免了一切可能的循环依赖,与多次构造依赖带来的内存泄露等很多难以排查的问题。
参考资料
InversifyJS Architecture Overview
相关文章:
浅析依赖注入框架的生命周期(以 InversifyJS 为例)
在上一篇介绍了 VSCode 的依赖注入设计,并且实现了一个简单的 IOC 框架。但是距离成为一个生产环境可用的框架还差的很远。 行业内已经有许多非常优秀的开源 IOC 框架,它们划分了更为清晰地模块来应对复杂情况下依赖注入运行的正确性。 这里我将以 Inv…...
HER2靶向药物研发进展-销售数据-上市药品前景分析
HER2长期作为肿瘤领域的热门靶点之一,其原因是它在多部位、多种形式的癌症中均有异常的表达,据研究表明HER2除了在胃癌、胆道癌、胆管癌、乳腺癌、卵巢癌、结肠癌、膀胱癌、肺癌、子宫颈癌、子宫浆液性子宫内膜癌、头颈癌、食道癌中的异常表达还存在于多…...
【第38天】不同路径数问题 | 网格 dp 入门
本文已收录于专栏🌸《Java入门一百例》🌸学习指引序、专栏前言一、网格模型二、【例题1】1、题目描述2、解题思路3、模板代码4、代码解析5.原题链接三、【例题2】1、题目描述2、解题思路3、模板代码4、代码解析5.原题链接三、推荐专栏四、课后习题序、专…...
LINUX之链接命令
链接命令学习目标能够说出软链接的创建方式能够说出硬链接的创建方式1. 链接命令的介绍链接命令是创建链接文件,链接文件分为:软链接硬链接命令说明ln -s创建软链接ln创建硬链接2. 软链接类似于Windows下的快捷方式,当一个源文件的目录层级比较深&#x…...
1628_MIT 6.828 xv6_chapter0操作系统接口
全部学习汇总: GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 这本书最初看名字以为是对早期unix的一个解读,但是看了开篇发现 不完全是,只是针对JOS教学OS系统来做的一些讲解。 Xv6是对UNIX v6的重新实…...
使用 Sahi 实现 Web 自动化测试
Sahi 是 Tyto Software 旗下的一个基于业务的开源 Web 应用自动化测试工具。Sahi 运行为一个代理服务器,并通过注入 JavaScript 来访问 Web 页面中的元素。Sahi 支持 HTTPS 并且独立于 Web 站点,简单小巧却功能强大。它相对于 Selenium 等自动化测试工具…...
天津菲图尼克科技携洁净及无菌防护服解决方案与您相约2023生物发酵展
BIO CHINA 生物发酵产业一年一度行业盛会,由中国生物发酵产业协会主办,上海信世展览服务有限公司承办,2023第10届国际生物发酵产品与技术装备展览会(济南)于2023年3月30-4月1日在山东国际会展中心(济南市槐…...
Java 网络编程详解
1、什么是网络编程 在网络通信协议下,不同计算机上运行的程序,可以进行数据传输。 应用场景: 1、即时通信 2、网游对战 3、邮件等等 Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序 2、网络编程三要素 2.1 IP地址 要…...
Scratch少儿编程案例-几何形式贪吃蛇
专栏分享 点击跳转=>Unity3D特效百例点击跳转=>案例项目实战源码点击跳转=>游戏脚本-辅助自动化点击跳转=>Android控件全解手册点击跳转=>Scratch编程案例👉关于作者...
一定要收藏的面试思维导图,粉丝分享面试经验
一位粉丝分享面试经验:1.常见面试题有哪些?主要从以下一些知识点做了准备: 常用的分析方法、Excel、SQL、 A/B测试、产品分析。然后每份面试针对职位要求,还有前期和HR聊天一点点了解这个职位之后,定向准备。 Excel、S…...
【博客615】通过systemd设置cgroup来限制服务资源争抢
通过systemd设置cgroup来限制服务资源争抢 1、场景 我们的宿主机上通常会用systemctl来管理一些agent服务,此时我们需要限制服务的cpu,memory等资源用量,以防止服务之前互相争抢资源,导致某些核心agent运行异常 2、systemd与cgro…...
C语言经典编程题100例(21-40)
21、练习3-2 计算符号函数的值对于任一整数n,符号函数sign(n)的定义如下:请编写程序计算该函数对任一输入整数的值。输入格式:输入在一行中给出整数n。输出格式:在一行中按照格式“sign(n) 函数值”输出该整数n对应的函数值。输入样例1:10输出样例1:sig…...
Rabbitmq业务难点
Rabbitmq业务难点1.消息生产者发送的消息无法路由到任何一个队列怎么处理?2.聊聊Rabbitmq的七种工作模式3.Rabbitmq的消息确认机制4.Rabbitmq的消息持久化5.发布确认模式如何确保生产者能够成功将消息投递到消息队列6. Rabbitmq基于队列设置消息过期时间和单独针对消息设置过期…...
服务器如何下载百度网盘文件?Linux服务器如何在百度网盘中连接、上传下载;在Linux服务器上下载百度云盘中的资料
前言 百度云提供Python包bypy进行远程服务器的对接然后下载: https://github.com/houtianze/bypy 可以通过pip直接下载,授权本人的百度云账号后,就可以直接使Linux电脑本地文件与百度网盘的apps(我的应用数据)/bypy目…...
Cesium-数字仿真-你总要了解
Cesium(专注于时空数据的实时可视化) cesium是一款三维地球开源框架(可以多平台、跨平台使用)cesium隶属于美国AGI公司(Analytical Graphics Incorporation),美国通用公司宇航部的工程师创始开源 周边产…...
原型、原型链、__proto__与prototype的区别、继承
一.什么是原型与原型链 根据MDN官方解释: JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象[[Prototype]] ,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类…...
前端 面经
1说一说cookie sessionStorage localStorage 区别?解题思路得分点 数据存储位置、生命周期、存储大小、写入方式、数据共享、发送请求时是否携带、应用场景 标准回答 Cookie、SessionStorage、 LocalStorage都是浏览器的本地存储。 它们的共同点:都是存储…...
[oeasy]python0080_设置RGB颜色_24bit_24位真彩色_颜色设置
RGB颜色 回忆上次内容 上次 首先了解了 索引颜色 \33[38;5;XXXm 设置 前景为索引色\33[48;5;XXXm 设置 背景为索引色 RGB每种颜色 可选0-5总共 6 级 想用 精确RGB值 真实地 大红色画个 大红桃心 ♥️ 有可能吗??🤔 rgb 模式 关于 RGB 模式…...
实战项目-用户评论数据情绪分析
目录1、基于词典的方法2、基于词袋或 Word2Vec 的方法2.1 词袋模型2.2 Word2Vec3、案例:用户评论情绪分析3.1 数据读取3.2 语料库分词处理3.3 Word2Vec 处理3.4 训练情绪分类模型3.5 对评论数据进行情绪判断目的:去判断一段文本、评论的情绪偏向在这里&a…...
day02 DOS(续)文本编辑快捷键 发展史
day02课堂笔记 1、常用的DOS命令(续) 1.1、del命令,删除一个或者多个文件 删除T1.class文件 C:\Users\Administrator>del T1.class 删除所有.class结尾的文件,支持模糊匹配 C:\Users\Administrator>del *.class T1.classT1…...
便携激光云高仪:精确测量云底高度、云层厚度等关键参数
便携激光云高仪是一种用于测量云层高度、厚度及分布情况的气象观测设备,广泛应用于气象监测、航空安全、环境研究等领域。其便携式设计特别适合野外作业和临时观测需求。设备通过激光脉冲探测云底高度,并实时分析云层垂直结构,为气象预报、灾…...
秀米能做的它都行,AI 写作让内容生产更简单
「选题想破头,初稿磨半天,排版更费神。」这或许是当下许多小编、运营乃至企业内容负责人的日常写照。内容需求暴涨,但高质量产出一直是道门槛。传统的编辑器,如秀米等,已极大简化了图文排版与可视化编辑的流程…...
AI辅助开发:让Kimi帮你写智能切换Win11右键菜单的脚本
今天想和大家分享一个实用的小技巧:如何用AI辅助开发,快速搞定Win11右键菜单的个性化定制。作为一个从Win7升级到Win11的老用户,我一直不太习惯新版右键菜单的折叠设计,特别是常用的"刷新"、"新建"选项需要多…...
OpenOCD入门到精通:第23章 添加新的 JTAG 适配器驱动
第23章 添加新的 JTAG 适配器驱动 导读摘要:OpenOCD 支持 40 余种调试适配器,每种适配器背后都有一个遵循统一接口规范的驱动程序。本章从 adapter_driver 结构体出发,逐一解析其回调函数语义,介绍 libusb/HIDAPI 通信层封装,并通过一个完整的简易驱动实现示例,帮助读者掌…...
3步解锁数据自由:WeChatMsg让聊天记录成为数字资产
3步解锁数据自由:WeChatMsg让聊天记录成为数字资产 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMs…...
ROS Noetic下大陆ARS408雷达点云数据解析:从CAN原始帧到RVIZ可视化,一个脚本全搞定
ROS Noetic下大陆ARS408雷达点云数据全链路解析与自动化实践 毫米波雷达在自动驾驶、机器人导航等领域扮演着关键角色。大陆ARS408作为一款高性价比的毫米波雷达,其点云数据的获取与可视化是许多开发者需要掌握的核心技能。本文将带您从底层CAN总线通信开始…...
3大突破:重新定义Revit插件开发流程
3大突破:重新定义Revit插件开发流程 【免费下载链接】RevitAddInManager Revit AddinManager update .NET assemblies without restart Revit for developer. 项目地址: https://gitcode.com/gh_mirrors/re/RevitAddInManager 引言:Revit插件开发…...
ESP32+BC260Y+L76K开发板实战:NB-IoT户外定位数据上传MQTT全流程(附避坑指南)
ESP32BC260YL76K开发板实战:NB-IoT户外定位数据上传MQTT全流程(附避坑指南) 在物联网应用快速发展的今天,户外定位数据的采集与传输已成为智慧农业、资产追踪、环境监测等领域的核心需求。ESP32作为一款高性价比的Wi-Fi/蓝牙双模芯…...
零基础玩转luci-app-unblockneteasemusic完全指南:从安装到多设备协同的3步进阶法
零基础玩转luci-app-unblockneteasemusic完全指南:从安装到多设备协同的3步进阶法 【免费下载链接】luci-app-unblockneteasemusic [OpenWrt] 解除网易云音乐播放限制 项目地址: https://gitcode.com/gh_mirrors/lu/luci-app-unblockneteasemusic luci-app-u…...
3分钟搞定!Windows 11 LTSC 24H2微软商店终极安装指南
3分钟搞定!Windows 11 LTSC 24H2微软商店终极安装指南 【免费下载链接】LTSC-Add-MicrosoftStore Add Windows Store to Windows 11 24H2 LTSC 项目地址: https://gitcode.com/gh_mirrors/ltscad/LTSC-Add-MicrosoftStore 你是否正在使用Windows 11 24H2 LTS…...
