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所采用的主要设计模式非 ...
随机推荐
- Devexpress VCL Build v2014 vol 14.1.4 发布
虽然这次没加什么新东西,但是及时更新支持xe7,还算可以. What's New in 14.1.4 (VCL Product Line) New Major Features in 14.1 W ...
- 前端之css笔记2
1 属性选择器 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...
- arduino uno r3 + SIM900 + USB打火机 实现电话触发点火
需求来源 1.儿子过完年6岁,喜欢玩烟花,但是胆子小,于是我就负责点火,从年前26到大年初八,每天晚上要给儿子点鞭炮啊点鞭炮. 2.这边过年要打关门炮跟开门炮,大年初一凌晨还要起来帮老妈点鞭炮,说实在 ...
- 基于beego orm 针对oracle定制
目前golang的ORM对oracle支持都没有mysql那样完整,一个orm要同时兼容mysql和oracle由于在sql语法上区别,会使整orm变的非常臃肿. 本项目是在beego orm上修改, ...
- C++之类和对象的使用(二)
析构函数 析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一系列清理工作,使这部分内存可以被程序分配给新对象使用.对象生命周期结束,程序就自动执行析构函数来完成这些工作. 析构函数是一种 ...
- VMware + LInux + Xshell 连接环境设置(心得体会)
准备好VMware软件,和Linux 和xshell三款软件,下载和安装好,这里VMware是十二,Linux是CentOs 6 ,xshell是5 其实没有什么区别只要版本兼容就行,我们就可以实现远 ...
- LA 3213 Ancient Cipher (水题,转化)
题意:给定两个长度相同的字符串,判断它们之间是否存在一一对应关系,顺序不定. 析:刚开始没看到顺序不定,然后写完没胡把样例看完就交了,结果WA了一次...其实这是一个水题,既然顺序不定,那么更简单,我 ...
- Easy CHM使用简明教程
近日整理硬盘,发现下载有许多DOC.JPEG.HTML等 格式的学习资料,也包括一些电子书资料:而其中的DOC.HTML等资料在学习浏览时显得很不方便,不同格式的文件需要使用不同的打开方式.近而发现电 ...
- SSH中设置字符编码防止乱码
1.在web.xml中加入一个过滤器和过滤范围的配置 <filter><filter-name>encoding</filter-name><filter-c ...
- 使用jetty-maven-plugin运行maven多项目
1.准备工作 org.eclipse.jetty jetty-maven-plugin 9.2.11.v20150529 jdk 1.7 maven 3.1 2.采用maven管理多项目 ...