深入
这篇SwiftSuspenders 浅出深入的 深入部分主要是对SwiftSuspenders进行深度剖析,包括对SwiftSuspenders的体系结构的分析,一个对象在整个注入过程中会经历怎样的生命周期,以及对SwiftSuspenders每个类的详细解读。
术语表
首先为了表达的明确性,先列下了一些可能在文章中用到的术语。这样便于减少理解上的歧义:
为了解释清楚术语之间的关系,我们设计以下场景以进行类比:闪闪同学生病了,需要进行打针治疗。
术语名 |
英文 |
解释 |
依赖 |
Dependency |
面向对象中类之间的关系,简单来说,当A类的某些功能需要B类进行辅助时,就说A类对B类有依赖。如闪闪同学需要药来治病,那么就说闪闪对药有依赖 |
注入 |
Injection |
一种建立依赖关系的行为。如闪闪同学要使用药,就必须让药进入体内(引用关系)。如何让药进入体内呢?需要一个针筒,通过注射来获得药物。这就是注入。当A和B的依赖关系由C来建立。B被C注入进了A。 |
注入器 |
Injector |
就是SwiftSuspenders里面的Injector类的一个实例,相当于扮演针筒的角色。 |
注入配置 |
InjectionConfig |
是针对一个注入行为的配置对象。包含注入请求的类和注入名。所使用的注入器和返回结果的策略等信息。如闪闪得的是感冒,需要注射感冒药,还需要注射消炎药,这时候闪闪就要请求两种类型的药。同一种类型的药,可能还有不同的品牌,所以有的时候还需要加上请求的药的名字,就相当于注入名。注入配置就相当于一张处方单。 |
注入点 |
InjectionPoint |
依赖注入分几种形式,如,构造函数注入,属性注入和方法注入。这些都称做注入点。比如打针,可以打PP,也可以打胳膊。属性注入就是对public的属性或者有setter方法进行复制,方法注入就是像某个函数传参。 |
注入描述 |
InjecteeDescription |
包含了一个被注入对象的所有的注入点。比如闪闪打针,需要在胳膊打一针,需要在屁股打两针。就会描述在注入描述里面。InjecteeDescription是Injector的一个包外类。 |
返回策略 |
InjectionResult |
反应了注入器以何种方式对请求进行注入,如直接新建一个B对象,然后注入A,或者以单例模式新建一个B对象,然后所有使用B的注入都会共享同一个对象等等。 |
体系结构
SwiftSuspenders的类图如上图所示。整个框架以Injector为核心。InjectionPoint包中包含了所有与注入点相关的类,InjectionResult包中包含了返回策略相关的类。其他的类都是配合Injector类进行工作。具体的类的解读会在下一章进行深入介绍。
其中用到的设计模式主要有策略模式,模板方法。
在InjectionResult包中主要使用了通过策略模式,作者针对不同的需求创造了不同的映射策略,如单例模式,类模式,对象模式。同时还允许开发者开发其他所需的策略。
在InjectionPoint包中主要使用了模板方法,通过让不同的子类实现initializeInjection这个钩子(hook)方法从而实现不同的注入点
对象生命周期
这一章主要从内部分析SwiftSuspender的两个主要活动:映射和注入的流程
映射顺序图
以mapClass为例,首先主程序调用Injector的mapClass方法,传入所需的参数;
然后Injector调用自身的getMapping方法,获得一个相应的注入配置对象,如果再此之前已经建立过相应的注入配置,则直接返回,如果没有,就会新建一个注入配置对象
获得注入配置对象后,就会调用得到的InjectionConfig的setResult方法设置该配置的返回策略。如为类映射是,就设置为InjectClassResult。如果是单例,则设置为InjectSingletonResult。以此类推。
最后返回设置好各项参数的InjectionConfig。同时该InjectionConfig对象就会存在Injector的m_mappings的Dictionary中。整个映射的过程就完成了。
注入顺序图
通过Injector的getInstance()方法可以获得注入后的对象。主程序通过向Injector发送类+注入名的请求以获得对象。
Injector得到请求后,调用自身的getConfigurationForRequest()方法获得相应的InjectionConfig注入配置.
获得注入配置后,调用InjectionConfig的getResponse()方法获得结果。
InjectionConfig的getResponse()方法会调用相应的InjectionResult返回策略的getResponse()方法获得结果。如果traverseAncestors设为true,那么当在当前的注入器中没有找到相应的注入配置时,还会从下至上依次遍历其祖先注入器,直到找到位置。
InjectionResult会调用Injector的instantiate()方法获得对象。
在Injector的instantiate方法会调用Injector的getInjectionPoints方法获得需要注入的类的所有的注入点。然后调用构造函数注入点先获得所请求类的实例。
在得到请求类的实例后,Injector会调用自身的InjectInto方法像这个对象的其他注入点进行依赖注入。
最后将注入完成的结果返回给程序。在注入的过程中,如果遇到被注入的对象仍然需要依赖注入,就会和上面的流程一样,对被注入的对象同样执行依赖注入,然后再将注入完的对象注入进目标对象。
转http://sswilliam.blog.163.com/blog/static/189696383201176114713922/