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

Swinject

核心是 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)

posted on 2019-01-19 21:01  花老🐯  阅读(952)  评论(0编辑  收藏  举报

导航