源码解读——Resolver

Resolver 是一个采用 Swift 编写的轻量级依赖注入/服务定位框架。关于依赖注入和服务定位的概念,可以阅读 《控制反转、依赖注入、服务定位》 一文。本文源码解读的 Resolver 版本是 1.5.0。
基本原理
Resolver 是一个依赖注入/服务定位框架,但是它的核心逻辑主要还是服务定位的典型设计实现。服务定位的设计通常包括两个主要步骤:
- 服务注册(Service Register)
 - 服务解析(Service Resolve)
 
服务注册通常是注册一个工厂方法,工厂方法能够根据相关参数可以实例化一个服务对象。由于允许注册多个服务,因此会有一个容器(Container)来存储这些工厂方法。通常情况下,会使用一个哈希表存储这些工厂方法,其中以服务的名称为键,以对应的工厂方法为值。这里我们暂且称这个哈希表为 注册项哈希表。
服务解析是指根据服务的名称在容器中查找对应的工厂方法,执行并返回一个服务对象的过程。通常情况下,会根据不同的需求采用不同的解析策略。比如:在某些场景下,每次都调用工厂方法初始化一个服务对象;在某些场景下,对于同一种服务只初始化一次,后续重复使用该服务对象。对于后一种情况,一般会使用另一个哈希表存储这些服务对象,其中以服务的名称为键,以对应的服务对象为值。这里我们暂且称这个哈希表为 缓存哈希表。
整体架构
在了解了服务定位的设计原理之后,我们再来看看 Resolver
的设计实现。下图所示为 Resolver
的类图,其中设计的核心在于红色虚线框中的部分,这里主要涉及到 3
个类:Resolver、ResolverRegistration、ResolverScope。这
3 个类基本覆盖了 Resolver 的主体逻辑,下面我们依次进行介绍。

ResolverRegistration
ResolverRegistration 从命名上看就知道是用来表示一个
注册项。如下所示,是 ResolverRegistration
的定义。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class ResolverRegistration<Service>: ResolverOptions<Service> {
    public var key: Int
    public var cacheKey: String
    public init(resolver: Resolver, key: Int, name: Resolver.Name?) {
        self.key = key
        if let namedService = name {
            self.cacheKey = String(key) + ":" + namedService.rawValue
        } else {
            self.cacheKey = String(key)
        }
        super.init(resolver: resolver)
    }
    public func resolve(resolver: Resolver, args: Any?) -> Service? {
        fatalError("abstract function")
    }
}
按照基本原理一节中的介绍,ResolverRegistration
按道理应该会定义工厂方法,但是这里我们只看到了关于 key 和
cacacheKey 的定义,这是什么情况?事实上,我们从
resolve(resolver: Resolver, args: Any?) -> Service?
方法的定义可以确定 ResolverRegistration
是一个抽象类。因此,我们需要再来看看它的子类。
ResolverRegistration 定义了三个子类,分别是:
ResolverRegistrationOnlyResolverRegistrationResolverResolverRegistrationArgumentsN
这三个子类的定义分别如下所示,可以发现,子类中定义了工厂方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56/// ResolverRegistration stores a service definition and its factory closure.
public final class ResolverRegistrationOnly<Service>: ResolverRegistration<Service> {
    public var factory: ResolverFactory<Service>
    public init(resolver: Resolver, key: Int, name: Resolver.Name?, factory: @escaping ResolverFactory<Service>) {
        self.factory = factory
        super.init(resolver: resolver, key: key, name: name)
    }
    public final override func resolve(resolver: Resolver, args: Any?) -> Service? {
        guard let service = factory() else {
            return nil
        }
        mutate(service, resolver: resolver, args: args)
        return service
    }
}
/// ResolverRegistrationResolver stores a service definition and its factory closure.
public final class ResolverRegistrationResolver<Service>: ResolverRegistration<Service> {
    public var factory: ResolverFactoryResolver<Service>
    public init(resolver: Resolver, key: Int, name: Resolver.Name?, factory: @escaping ResolverFactoryResolver<Service>) {
        self.factory = factory
        super.init(resolver: resolver, key: key, name: name)
    }
    public final override func resolve(resolver: Resolver, args: Any?) -> Service? {
        guard let service = factory(resolver) else {
            return nil
        }
        mutate(service, resolver: resolver, args: args)
        return service
    }
}
/// ResolverRegistrationArguments stores a service definition and its factory closure.
public final class ResolverRegistrationArgumentsN<Service>: ResolverRegistration<Service> {
    public var factory: ResolverFactoryArgumentsN<Service>
    public init(resolver: Resolver, key: Int, name: Resolver.Name?, factory: @escaping ResolverFactoryArgumentsN<Service>) {
        self.factory = factory
        super.init(resolver: resolver, key: key, name: name)
    }
    public final override func resolve(resolver: Resolver, args: Any?) -> Service? {
        guard let service = factory(resolver, Resolver.Args(args)) else {
            return nil
        }
        mutate(service, resolver: resolver, args: args)
        return service
    }
}
此外,我们还发现,这三个类的内部逻辑几乎一模一样,唯一的区别在于工厂方法的类型不一样,分别是:
ResolverFactory<Service>ResolverFactoryResolver<Service>ResolverFactoryArgumentsN<Service>
这三种工厂的定义分别如下,可以看出它们都是用于初始化服务的工厂方法,区别在于服务的初始化入参不同,有些需要参数,有些不需要,有些甚至连
Resolver 都不需要。 1
2
3public typealias ResolverFactory<Service> = () -> Service?
public typealias ResolverFactoryResolver<Service> = (_ resolver: Resolver) -> Service?
public typealias ResolverFactoryArgumentsN<Service> = (_ resolver: Resolver, _ args: Resolver.Args) -> Service?
从这三个类对于 resolve
的实现来看可以发现,它们才是服务初始化的真正执行者。
看完 ResolverRegistration 的子类后,我们再来看它的父类
ResolverOptions,具体如下所示: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48public class ResolverOptions<Service> {
    // MARK: - Parameters
    public var scope: ResolverScope
    fileprivate var mutator: ResolverFactoryMutator<Service>?
    fileprivate var mutatorWithArgumentsN: ResolverFactoryMutatorArgumentsN<Service>?
    fileprivate weak var resolver: Resolver?
    // MARK: - Lifecycle
    public init(resolver: Resolver) {
        self.resolver = resolver
        self.scope = Resolver.defaultScope
    }
    
    @discardableResult
    public final func implements<Protocol>(_ type: Protocol.Type, name: Resolver.Name? = nil) -> ResolverOptions<Service> {
        resolver?.register(type.self, name: name) { r, _ in r.resolve(Service.self) as? Protocol }
        return self
    }
    
    @discardableResult
    public final func resolveProperties(_ block: @escaping ResolverFactoryMutator<Service>) -> ResolverOptions<Service> {
        mutator = block
        return self
    }
    
    @discardableResult
    public final func resolveProperties(_ block: @escaping ResolverFactoryMutatorArgumentsN<Service>) -> ResolverOptions<Service> {
        mutatorWithArgumentsN = block
        return self
    }
    
    @discardableResult
    public final func scope(_ scope: ResolverScope) -> ResolverOptions<Service> {
        self.scope = scope
        return self
    }
    
    fileprivate func mutate(_ service: Service, resolver: Resolver, args: Any?) {
        self.mutator?(resolver, service)
        if let mutatorWithArgumentsN = mutatorWithArgumentsN {
            mutatorWithArgumentsN(resolver, service, Resolver.Args(args))
        }
    }
}
从 ResolverOptions 的属性上看,在结合
ResolverRegistration
及其子类的定义,我们可以知道一个注册项的定义大致包含如下这些内容:
factory: 工厂方法,用于初始化服务对象,可以有三种工厂方法。key:用于服务注册的注册项哈希表中的键。cacheKey:用于服务解析的缓存哈希表中的键。resolver:Resolver类型,它是服务注册的核心实现,内部维护一个注册项哈希表,同时也是与用户打交道的类,可以认为是 Service Locator。scope:ResolverScope类型,它是服务解析的核心实现,内部维护一个缓存哈希表。mutator:ResolverFactoryMutator<Service>?类型,允许用户对初始化后的服务对象进行额外的修改。mutator:ResolverFactoryMutatorArgumentsN<Service>?类型,允许用户使用参数对初始化后的服务对象进行额外的修改。

ResolverScope
在上一节中,我们提到了 ResolverScope
主要负责服务解析,此外内部维护了一个缓存哈希表。下面,我们来深入分析一下,如下所示为
ResolverScope 的定义。
1  | public class ResolverScope: ResolverScopeType {  | 
从 resolve 的实现来看,我们也能够确认
ResolverScope
是一个抽象类。除此之外,它还定义了几个静态变量。这几个静态变量的类型都是
ResolverScope 的子类,而且类型有所不同。
下面,我们来看看它的子类。
ResolverScopeCache
ResolverScopeCache
的定义如下,其内部维护了一个缓存哈希表
cacahedServices。另外,它定义了一套自己的服务解析策略,从
resolve 方法可以看出大致的策略如下:
- 根据注册项的 
cacheKey查找服务对象,如果查到,则直接返回对应的服务对象;否则,进入步骤 2 - 调用服务初始化的真正执行者 
ResolverRegistration的resolve方法进行初始化服务对象。 - 如果初始化完成,则加入缓存哈希表进行缓存。
 - 最后,返回服务对象。
 
此外,ResolverScopeCache 还提供一个 reset
方法,可以清空缓存哈希表。
1  | /// Cached services exist for lifetime of the app or until their cache is reset.  | 
ResolverScopeGraph
ResolverScopeGraph
的定义如下所示,它也持有一个缓存哈希表,其服务解析策略与
ResolverScopeCache
大同小异,区别在于:它在一次解析周期中对于相同的服务只解析一次,当一次解析周期完毕后,自动清空缓存哈希表。
1  | /// Graph services are initialized once and only once during a given resolution cycle. This is the default scope.  | 
ResolverScopeShare
ResolverScopeShare
的定义如下所示,其内部同样持有一个缓存哈希表,它的解析策略也是优先查找缓存哈希表,如果找不到,则初始化服务对象并存入缓存。不过它通过一个封装类型弱引用了服务对象,从而允许服务对象被共享。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26/// Shared services persist while strong references to them exist. They're then deallocated until the next resolve.
public final class ResolverScopeShare: ResolverScope {
    public override init() {}
    public final override func resolve<Service>(resolver: Resolver, registration: ResolverRegistration<Service>, args: Any?) -> Service? {
        if let service = cachedServices[registration.cacheKey]?.service as? Service {
            return service
        }
        let service = registration.resolve(resolver: resolver, args: args)
        if let service = service, type(of: service as Any) is AnyClass {
            cachedServices[registration.cacheKey] = BoxWeak(service: service as AnyObject)
        }
        return service
    }
    public final func reset() {
        cachedServices.removeAll()
    }
    private struct BoxWeak {
        weak var service: AnyObject?
    }
    private var cachedServices = [String : BoxWeak](minimumCapacity: 32)
}
ResolverScopeUnique
ResolverScopeUnique
的定义如下所示,它内部并没有缓存哈希表,因此每一次进行服务解析时,它都会重新初始化一个服务对象。
1
2
3
4
5
6
7
8
9/// Unique services are created and initialized each and every time they're resolved.
public final class ResolverScopeUnique: ResolverScope {
    public override init() {}
    public final override func resolve<Service>(resolver: Resolver, registration: ResolverRegistration<Service>, args: Any?) -> Service? {
        return registration.resolve(resolver: resolver, args: args)
    }
}
ResolverScopeContainer
ResolverScopeContainer
的定义如下所示,它内部没有缓存哈希表,它的解析策略是让 Resolver 的
ResolverScopeCache 来代理执行服务解析。 1
2
3
4
5
6
7
8
9/// Proxy to container's scope. Cache type depends on type supplied to container (default .cache)
public final class ResolverScopeContainer: ResolverScope {
    public override init() {}
    public override final func resolve<Service>(registration: ResolverRegistration<Service>, resolver: Resolver, args: Any?) -> Service? {
        return resolver.cache.resolve(registration: registration, resolver: resolver, args: args)
    }
}
Resolver
Resolver
是服务注册的核心,也是与用户直接打交道的类,用户通过调用它提供的方法进行注册和解析。
下面,我们来看一下 Resolver
的实现,由于它的代码较多,这里进行了部分删减,具体如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public final class Resolver {
    // MARK: - Defaults
    /// Default registry used by the static Registration functions.
    public static var main: Resolver = Resolver()
    /// Default registry used by the static Resolution functions and by the Resolving protocol.
    public static var root: Resolver = main
    /// Default scope applied when registering new objects.
    public static var defaultScope: ResolverScope = .graph
    
    // MARK: - Lifecycle
    public init(parent: Resolver? = nil) {
        self.parent = parent
    }
    
    ...
    
    @discardableResult
    public final func register<Service>(_ type: Service.Type = Service.self, name: Resolver.Name? = nil,
                                        factory: @escaping ResolverFactory<Service>) -> ResolverOptions<Service> {
        lock.lock()
        defer { lock.unlock() }
        let key = ObjectIdentifier(Service.self).hashValue
        let registration = ResolverRegistrationOnly(resolver: self, key: key, name: name, factory: factory)
        add(registration: registration, with: key, name: name)
        return registration
    }
    
    ...
    
    public final func resolve<Service>(_ type: Service.Type = Service.self, name: Resolver.Name? = nil, args: Any? = nil) -> Service {
        lock.lock()
        defer { lock.unlock() }
        registrationCheck()
        if let registration = lookup(type, name: name),
            let service = registration.scope.resolve(resolver: self, registration: registration, args: args) {
            return service
        }
        fatalError("RESOLVER: '\(Service.self):\(name?.rawValue ?? "NONAME")' not resolved. To disambiguate optionals use resolver.optional().")
    }
    
    ...
    
    // MARK: - Internal
    /// Internal function searches the current and parent registries for a ResolverRegistration<Service> that matches
    /// the supplied type and name.
    private final func lookup<Service>(_ type: Service.Type, name: Resolver.Name?) -> ResolverRegistration<Service>? {
        let key = ObjectIdentifier(Service.self).hashValue
        let containerName = name?.rawValue ?? NONAME
        if let container = registrations[key], let registration = container[containerName] {
            return registration as? ResolverRegistration<Service>
        }
        if let parent = parent, let registration = parent.lookup(type, name: name) {
            return registration
        }
        return nil
    }
    /// Internal function adds a new registration to the proper container.
    private final func add<Service>(registration: ResolverRegistration<Service>, with key: Int, name: Resolver.Name?) {
        if var container = registrations[key] {
            container[name?.rawValue ?? NONAME] = registration
            registrations[key] = container
        } else {
            registrations[key] = [name?.rawValue ?? NONAME : registration]
        }
    }
    private let NONAME = "*"
    private let parent: Resolver?
    private let lock = Resolver.lock
    private var registrations = [Int : [String : Any]]()
}
从源码中可以看出,Resolver 内部维护了一个注册项哈希表
registrations。
当用户调用 register
方法进行服务注册时,首先会在内部初始化一个注册项(
ResolverRegistration 的子类)。然后,调用 add
方法将注册项存入注册项哈希表中。
当用户调用 resolve 方法进行服务解析时,首先会调用
loopup
方法查找注册项哈希表中对应的注册项,然后调用注册项对应的 scope
进行服务解析,本质上服务的初始化最终还是由注册项完成。
在 Resolver 中,默认使用的 ResolverScope 是
ResolverScopeGraph
类型,当然我们也可以在注册时,通过调用注册项的 scope
方法进行切换。
我们仔细阅读 loopup 方法和 init
方法,可以发现,Resolver 可以其实是可以构成一棵
Resolver 树,在查找注册项时,会递归地查找父级
Resolver 中的注册项哈希表。
Resolving 协议
Resolver
为服务注册和服务解析同时实现了两套方法——静态方法和实例方法。
当我们使用静态方法时,对应的 Resolver 对象是一个全局变量
root 或 main,两者其实是同一个
Resolver 对象。
当我们使用实例方法时,首先我们需要初始化一个 Resolver
对象。对此,框架提供了一个 Resolving
协议,并扩展了默认实现,如下所示。这样的话,遵循了
Resolving 协议的类会自动扩展了一个 Resolver
类型的属性,并且执行修改类型。 1
2
3
4
5
6
7
8
9public protocol Resolving {
    var resolver: Resolver { get }
}
extension Resolving {
    public var resolver: Resolver {
        return Resolver.root
    }
}
注解注入
Resolver
除了完整实现了一套服务定位架构之外,还支持了注解注入。它提供了五种类型的注解,底层使用
propertyWrapper 实现的,分别如下:
Injected<Service>OptionalInjected<Service>LazyInjected<Service>WeakLazyInjected<Service>InjectedObject<Service>
使用注解的前提是,服务必须提前进行注册,因为注解在初始化时会立即进行服务解析。不过,LazyInjected<Service>
和 WeakLazyInjected<Service>
并无此要求,对于它们,只需要在调用前进行服务注册即可。
设计模式
Resolver 框架其实采用了 策略模式 进行设计实现的。
当服务注册时,Resolver 依赖的是抽象类
ResolverRegistration,框架提供了三种具体类型的
ResolverRegistration。当已有类型满足不了需求时,我们可以对
Resolver 的 register 方法进行重载,并自定义
ResolverRegistration 子类。
当服务注册时,Resolver 依赖的同样是抽象类
ResolverScope,框架提供两个五种具体类型的
ResolverScope
以提供不同的解析策略。当已有类型满足不了需求时,我们同样可以自定义
ResolverScope 子类实现定制的解析策略。
总结
本文对 Resolver 源码进行了解读,分析其整体框架的设计。Resolver
的核心主要包含三个部分:ResolverRegistration、ResolverScope、Resolver,它们各有各的职责,遵循了职责单一的设计原则,并且实现了一个扩展性很强的策略模式。
我认为 Resolver 非常适合作为重构的一套辅助工具,希望后面能够在实际开发中使用一下,从而能够在实践中提高一下自己的架构设计能力。