核心是 Container类。它提供了两类方法,registerresolve

为了找到在 resolve 时,能够找到对应的方法,内部维护了一个叫做services 的字典。key 是根据 serviceTypenameargumentsType 确定的。
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)
}
}

由于 ServiceKeynameserviceTypeargumentsType 都考虑在内了,所以下面两个注册,对应的是不同的 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)。
在初始化时,会把 serviceTypeargumentsType、component 的构造方法factory 作为参数传递。
resolve时,如有必要会取出 ServiceEntryfactory,然后结合传过来的参数,调用 factory 生成一个 component(即实例)

let resolvedInstance = invoker(entry.factory as! Factory)

Swinject 源码框架(一):基本原理的更多相关文章

  1. Swinject 源码框架(二):循环依赖的解决

    可能存在循环依赖,比如 Parent 强制有 Child, Child 弱持有 Parent. 具体实现如下.Parent 初始化时,必须传入 Child,而 Child 初始化不必传入 Parent ...

  2. Swinject 源码框架(三):Object Scopes

    Object Scopes 指定了生成的实例在系统中是如何被共享的. 如何指定 scope container.register(Animal.self) { _ in Cat() } .inObje ...

  3. TVM源码框架安装方法

    TVM源码框架安装方法 本文提供如何在各种系统上从零构建和安装TVM包的说明.它包括两个步骤: 首先从C++代码中构建共享库(linux的libtvm.so,macOS的libtvm.dylib和wi ...

  4. TensorFlow源码框架 杂记

    一.为什么我们需要使用线程池技术(ThreadPool) 线程:采用“即时创建,即时销毁”策略,即接受请求后,创建一个新的线程,执行任务,完毕后,线程退出: 线程池:应用软件启动后,立即创建一定数量的 ...

  5. vue2源码框架和流程分析

    vue整体框架和主要流程分析 之前对看过比较多关于vue源码的文章,但是对于整体框架和流程还是有些模糊,最后用chrome debug对vue的源码进行查看整理出这篇文章.... 本文对vue的整体框 ...

  6. golang 移动应用例子 example/basic 源码框架分析

    条件编译 我们在源码中可以看到2个文件: main.go 和 main_x.go 这两个包名都是 package main , 都有 main 函数. 不会冲突么? 答案是不会的, main_x.go ...

  7. jQuery源码框架fn解读

    (function( window, undefined ){ var jQuery = (function(){ var jQuery = function( selector, context ) ...

  8. Jmeter源码框架

    首先jmeter框架入口类: NewDriver类(src/core/org/apache/jmeter/NewDriver.java) public static void main(String[ ...

  9. MJRefresh源码框架分析

    MJRefresh是一款非常优秀的刷新控件.代码简洁,优雅.今天有时间对源代码阅读了一下.对MJRefresh的宏观设计非常赞叹.所谓大道至简就是这样吧.   MJRefresh所采用的主要设计模式非 ...

随机推荐

  1. fastjson解析List对象

    List<String[]> body = JSON.parseObject(msg.getBody().toString(), new TypeToken<List<Stri ...

  2. sci-hub 下载地址更新

    #  2017-12-14 可用 http://www.sci-hub.tw/ 文献共享平台

  3. 构造函数constructor 与析构函数destructor(二)

    (1)转换构造函数 转换构造函数的定义:转换构造函数就是把普通的内置类型转换成类类型的构造函数,这种构造函数只有一个参数.只含有一个参数的构造函数,可以作为两种构造函数,一种是普通构造函数用于初始化对 ...

  4. c++中类的静态数据成员

    有时需要为某个类的所有对象分配一个单一的存储空间,这个存储空间只是被这个类的对象访问,其他人不能访问,那么这时静态的成员变量是有用的.例如下面用来统计一共创建了多少个对象的变量num class cl ...

  5. 高性能 js -- 无阻塞加载脚本

    参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...

  6. kbmMWEncodeEscapes 中汉字编码的问题及解决办法

    kbmMWEncodeEscapes 是kbmmw 里面的一个函数,用来对URL 中的汉字进行编码,例如 http://127.0.0.1/getname?name=春节,由于'春节'是汉字,浏览器向 ...

  7. 2018.09.26 bzoj5218: [Lydsy2017省队十连测]友好城市(回滚莫队)

    传送门 比较简单的一道回滚莫队吧. 每次询问用bitset优化kosaraju统计答案. 就是有点难调. 然后向dzyo学长学习了回滚莫队的一种简洁的实现方式,就是直接建立一个sqrt(m)∗sqrt ...

  8. 2018.07.08 hdu1394 Minimum Inversion Number(线段树)

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...

  9. hdu-2159(完全背包)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路:完全背包,但有次数的限制,因此,对次数进行dp,判断次数是否超限. #include< ...

  10. KindEditor解决上传视频不能在手机端显示的问题

    KindEditor自带的上传视频生成的HTML代码为<embed>,在手机端并不支持.于是可以自己在控件里增加生成video标签相关代码. 参考https://www.jianshu.c ...