Swinject 源码框架(一):基本原理

核心是 Container类。它提供了两类方法,register 和 resolve。
为了找到在 resolve 时,能够找到对应的方法,内部维护了一个叫做services 的字典。key 是根据 serviceType、name、argumentsType 确定的。
在 register 时,会字典里加入一个条目。在 resolve 时,会根据字典,找到对应的 ServiceEntryProtocol,然后调用其方法生成一个 component。
Container 类
register 方法
public func _register<Service, Arguments>(
_ serviceType: Service.Type,
factory: @escaping (Arguments) -> Any,
name: String? = nil,
option: ServiceKeyOption? = nil
) -> ServiceEntry<Service> {
let key = ServiceKey(serviceType: Service.self, argumentsType: Arguments.self, name: name, option: option)
let entry = ServiceEntry(
serviceType: serviceType,
argumentsType: Arguments.self,
factory: factory,
objectScope: defaultObjectScope
)
entry.container = self
services[key] = entry
behaviors.forEach { $0.container(self, didRegisterType: serviceType, toService: entry, withName: name) }
return entry
}
如上所示,先生成了一个 ServiceKey,然后生成了一个 ServiceEntry,再把这两个值在字典里对应。
resolve 方法
var resolvedInstance: Service?
let key = ServiceKey(serviceType: Service.self, argumentsType: Arguments.self, name: name, option: option)
if let entry = getEntry(for: key) {
resolvedInstance = resolve(entry: entry, invoker: invoker)
}
if resolvedInstance == nil {
resolvedInstance = resolveAsWrapper(name: name, option: option, invoker: invoker)
}
即先生成一个 ServiceKey,然后根据这个 key 找到一个 ServiceEntry,然后根据这个 entry 和传入的方法,生成一个实例,返回。
ServiceKey
ServiceKey 是一个结构体,用来标识注册的一个服务。
// MARK: - ServiceKey
internal struct ServiceKey {
internal let serviceType: Any.Type
internal let argumentsType: Any.Type
internal let name: String?
}
// MARK: Hashable
extension ServiceKey: Hashable {
var hashValue: Int {
return ObjectIdentifier(serviceType).hashValue
^ ObjectIdentifier(argumentsType).hashValue
^ (name?.hashValue ?? 0)
}
}
由于 ServiceKey 把 name、serviceType、argumentsType 都考虑在内了,所以下面两个注册,对应的是不同的 ServiceKey。 因为参数的类型不一样。
第一个参数类型是(String, Bool),第二个参数类型是 (Bool, String)。
container.register(Animal.self) { _, name, running in
Horse(name: name, running: running)
}
container.register(Animal.self) { _, running, name in
Horse(name: name, running: running)
}
ServiceEntry
ServiceEntry 实现了 ServiceEntryProtocol 方法,用来保存对应 ServiceKey 生产的实例,以及控制对象的范围(Object Scopes)。
在初始化时,会把 serviceType、argumentsType、component 的构造方法factory 作为参数传递。
在 resolve时,如有必要会取出 ServiceEntry 的 factory,然后结合传过来的参数,调用 factory 生成一个 component(即实例)
let resolvedInstance = invoker(entry.factory as! Factory)
Swinject 源码框架(一):基本原理的更多相关文章
- Swinject 源码框架(二):循环依赖的解决
可能存在循环依赖,比如 Parent 强制有 Child, Child 弱持有 Parent. 具体实现如下.Parent 初始化时,必须传入 Child,而 Child 初始化不必传入 Parent ...
- Swinject 源码框架(三):Object Scopes
Object Scopes 指定了生成的实例在系统中是如何被共享的. 如何指定 scope container.register(Animal.self) { _ in Cat() } .inObje ...
- TVM源码框架安装方法
TVM源码框架安装方法 本文提供如何在各种系统上从零构建和安装TVM包的说明.它包括两个步骤: 首先从C++代码中构建共享库(linux的libtvm.so,macOS的libtvm.dylib和wi ...
- TensorFlow源码框架 杂记
一.为什么我们需要使用线程池技术(ThreadPool) 线程:采用“即时创建,即时销毁”策略,即接受请求后,创建一个新的线程,执行任务,完毕后,线程退出: 线程池:应用软件启动后,立即创建一定数量的 ...
- vue2源码框架和流程分析
vue整体框架和主要流程分析 之前对看过比较多关于vue源码的文章,但是对于整体框架和流程还是有些模糊,最后用chrome debug对vue的源码进行查看整理出这篇文章.... 本文对vue的整体框 ...
- golang 移动应用例子 example/basic 源码框架分析
条件编译 我们在源码中可以看到2个文件: main.go 和 main_x.go 这两个包名都是 package main , 都有 main 函数. 不会冲突么? 答案是不会的, main_x.go ...
- jQuery源码框架fn解读
(function( window, undefined ){ var jQuery = (function(){ var jQuery = function( selector, context ) ...
- Jmeter源码框架
首先jmeter框架入口类: NewDriver类(src/core/org/apache/jmeter/NewDriver.java) public static void main(String[ ...
- MJRefresh源码框架分析
MJRefresh是一款非常优秀的刷新控件.代码简洁,优雅.今天有时间对源代码阅读了一下.对MJRefresh的宏观设计非常赞叹.所谓大道至简就是这样吧. MJRefresh所采用的主要设计模式非 ...
随机推荐
- fastjson解析List对象
List<String[]> body = JSON.parseObject(msg.getBody().toString(), new TypeToken<List<Stri ...
- sci-hub 下载地址更新
# 2017-12-14 可用 http://www.sci-hub.tw/ 文献共享平台
- 构造函数constructor 与析构函数destructor(二)
(1)转换构造函数 转换构造函数的定义:转换构造函数就是把普通的内置类型转换成类类型的构造函数,这种构造函数只有一个参数.只含有一个参数的构造函数,可以作为两种构造函数,一种是普通构造函数用于初始化对 ...
- c++中类的静态数据成员
有时需要为某个类的所有对象分配一个单一的存储空间,这个存储空间只是被这个类的对象访问,其他人不能访问,那么这时静态的成员变量是有用的.例如下面用来统计一共创建了多少个对象的变量num class cl ...
- 高性能 js -- 无阻塞加载脚本
参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...
- kbmMWEncodeEscapes 中汉字编码的问题及解决办法
kbmMWEncodeEscapes 是kbmmw 里面的一个函数,用来对URL 中的汉字进行编码,例如 http://127.0.0.1/getname?name=春节,由于'春节'是汉字,浏览器向 ...
- 2018.09.26 bzoj5218: [Lydsy2017省队十连测]友好城市(回滚莫队)
传送门 比较简单的一道回滚莫队吧. 每次询问用bitset优化kosaraju统计答案. 就是有点难调. 然后向dzyo学长学习了回滚莫队的一种简洁的实现方式,就是直接建立一个sqrt(m)∗sqrt ...
- 2018.07.08 hdu1394 Minimum Inversion Number(线段树)
Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...
- hdu-2159(完全背包)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路:完全背包,但有次数的限制,因此,对次数进行dp,判断次数是否超限. #include< ...
- KindEditor解决上传视频不能在手机端显示的问题
KindEditor自带的上传视频生成的HTML代码为<embed>,在手机端并不支持.于是可以自己在控件里增加生成video标签相关代码. 参考https://www.jianshu.c ...