StrangeIoC的设计和RobotLegs一致,所以我的解析会对照RobotLegs来看。

整个框架使用的是MVCS的模式,关于MVCS模式大家可以点这里进行查看,这里就不谈了,既然StrangeIoC称为依赖注入框架,我们就直接谈这个框架的注入实现。

中介类的生命周期

为啥不先说注入呢?因为自动创建和销毁中介类是我认为这个框架设计得最精彩的地方。

大家一定很好奇,当我们挂载了View脚本的GameObject添加到场景时,对应的中介类就会生成并绑定到该GameObject之上,同时中介类会通过注入获取到View的实例,而当GameObject被销毁时中介类也会被移除,下面我们一起看看这里面的玄机吧。

自动实例化中介类

首先所有的视图脚本都必须继承自View类,所以我们要揭开自动实例化的秘密就必须先从这个类入手,我们先看看View类的Awake和Start方法:

 /// A MonoBehaviour Awake handler.
/// The View will attempt to connect to the Context at this moment.
protected virtual void Awake ()
{
if (!registeredWithContext)
bubbleToContext(this, true, false);
} /// A MonoBehaviour Start handler
/// If the View is not yet registered with the Context, it will
/// attempt to connect again at this moment.
protected virtual void Start ()
{
if (!registeredWithContext)
bubbleToContext(this, true, true);
}

(注意:这里的方法并不是默认的void Start之类的写法,而是作为保护的虚函数进行定义的,这样可以使我们的子类进行对应的扩展。)

下面我们看看这段代码的意思是啥:

两个方法一致,这里判断的意思是:如果还没有在Context中进行注册,则先通过冒泡的方式找到Context(所谓的冒泡就是递归寻找父级对象,如果找到包含了ContextView脚本的父级对象,则认为是找到了Context,这也是为啥所有需要注入功能的GameObject都必须作为子孙对象被放在包含了ContextView脚本的GameObject中的原因。),并告诉它添加了一个视图对象。

(为了省事,干脆就把所有的GameObject都放在包含ContextView脚本的GameRoot下吧。)

接下来框架会从我们在Context中注册的信息里找到这个视图对应的中介类类型,并创建它添加到GameObject中,代码在MediationBinder的mapView中,如下:

 /// Creates and registers one or more Mediators for a specific View instance.
/// Takes a specific View instance and a binding and, if a binding is found for that type, creates and registers a Mediator.
virtual protected void mapView(IView view, IMediationBinding binding)
{
Type viewType = view.GetType(); if (bindings.ContainsKey(viewType))
{
object[] values = binding.value as object[];
int aa = values.Length;
for (int a = ; a < aa; a++)
{
MonoBehaviour mono = view as MonoBehaviour;
Type mediatorType = values [a] as Type;
if (mediatorType == viewType)
{
throw new MediationException(viewType + "mapped to itself. The result would be a stack overflow.", MediationExceptionType.MEDIATOR_VIEW_STACK_OVERFLOW);
}
MonoBehaviour mediator = mono.gameObject.AddComponent(mediatorType) as MonoBehaviour;
if (mediator is IMediator)
((IMediator)mediator).PreRegister ();
injectionBinder.Bind (viewType).ToValue (view).ToInject(false);
injectionBinder.injector.Inject (mediator);
injectionBinder.Unbind(viewType);
if (mediator is IMediator)
((IMediator)mediator).OnRegister ();
}
}
}

我们可以在19行看到中介类被添加了。

RobotLegs的做法

AS3中一个显示对象添加到舞台时会触发对应的事件,RobotLegs就是通过监听这个事件,在这个事件中创建中介类的。而StrangeIoC使用的是Awake和Start事件,也可以理解为添加到场景。

自动销毁中介类

销毁我们倒回来看看View类中的OnDestroy方法:

 /// A MonoBehaviour OnDestroy handler
/// The View will inform the Context that it is about to be
/// destroyed.
protected virtual void OnDestroy ()
{
bubbleToContext(this, false, false);
}

逻辑与Awake和Start一致,不同的是传递的参数不一致,这里也是通过冒泡找到Context并告诉它我移除了一个视图对象,框架会找到这个中介类并调用其OnRemove方法,代码在MediationBinder的unmapView中,如下:

 /// Removes a mediator when its view is destroyed
virtual protected void unmapView(IView view, IMediationBinding binding)
{
Type viewType = view.GetType(); if (bindings.ContainsKey(viewType))
{
object[] values = binding.value as object[];
int aa = values.Length;
for (int a = ; a < aa; a++)
{
Type mediatorType = values[a] as Type;
MonoBehaviour mono = view as MonoBehaviour;
IMediator mediator = mono.GetComponent(mediatorType) as IMediator;
if (mediator != null)
{
mediator.OnRemove();
}
}
}
}

下面我们来看看注入是怎么实现的。

RobotLegs的做法

同样AS3中一个显示对象从舞台移除时也会触发对应的事件,通过监听这个事件就可以移除对应的中介类了。

注入是如何实现的?

刚开始使用这个框架的童鞋肯定会惊叹于为什么写了[Inject]以后就可以自动获取对应的对象的实例,这种技术称为注入,其实原理很简单,就是使用了Attribute和反射两种特性而已。

我们还是以中介类为例子来看,中介类被创建后会进行注入,其中最重要的就是注入对应的视图脚本对象。代码在MediationBinder的mapView中,如下:

 injectionBinder.Bind (viewType).ToValue (view).ToInject(false);
injectionBinder.injector.Inject (mediator);
injectionBinder.Unbind(viewType);

这3行的解析如下:

  1. 记录添加的视图脚本对象,绑定到视图类型上;
  2. 对中介类进行注入,当发现有[Inject]的标签的属性时,同时类型为视图类型,则将上一步记录的视图脚本实例赋值给他;
  3. 注入完毕,取消记录的视图脚本对象。

那么注入的核心逻辑呢?我们来看看Injector类的Inject方法:

 public object Inject(object target, bool attemptConstructorInjection)
{
failIf(binder == null, "Attempt to inject into Injector without a Binder", InjectionExceptionType.NO_BINDER);
failIf(reflector == null, "Attempt to inject without a reflector", InjectionExceptionType.NO_REFLECTOR);
failIf(target == null, "Attempt to inject into null instance", InjectionExceptionType.NULL_TARGET); //Some things can't be injected into. Bail out.
Type t = target.GetType ();
if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(string))
{
return target;
} IReflectedClass reflection = reflector.Get (t); if (attemptConstructorInjection)
{
target = performConstructorInjection(target, reflection);
}
performSetterInjection(target, reflection);
postInject(target, reflection);
return target;
}

最开始的3行是做异常判断的;

下面有一个判断,如果是原生类型、数字或字符串就不处理了;

接下来会取出要被注入的对象的所有反射信息;

再接下来就是进行注入,解析如下:

  1. 如果要对构造函数的参数进行注入则进行构造函数参数的注入;
  2. 对属性进行注入;
  3. 对标记了[PostConstruct]标签的方法进行调用;
  4. 返回目标对象,此时注入已经完成。

注入实现解说

好吧,还是没搞懂注入究竟是怎么实现的?下面就大概说一下思路,不看代码了:

答案就是:使用反射获取类的所有信息,而Attribute可以为类、方法、属性等添加标记,这些标记也是可以由反射获得的,那么框架就可以知道什么属性是需要注入的了,只要这个属性被[Inject]标记即可,框架找到这些属性,通过类型判断按Context中注册的规则(比如是否为单例类型等)将对象的实例赋值给该属性。

一些其他的知识点

ToSingleton

作为单例注入,其作用是保证每次通过[Inject]标签获取的对象都是同一个对象,即只有一个实例,该实例在第一次获取时进行创建。

如果不作为单例注入,则每次通过[Inject]标签获取的对象都是新创建的实例,哪怕是同一个类写了2个[Inject]同一类型的对象,获取的实例也是两个不同的对象(虽然类型相同)。

dispatcher和IEvent

整个框架内部进行消息传递都靠这个类实现;

但是整个框架中其实存在两种dispatcher,一种负责在MVCS之间进行消息传递(注意这里的V指的是中介类),还有一种是负责视图类发送消息给中介类的dispatcher;

两种dispatcher不通用,即一种发送的消息另一种不会收到。

Once和InSequence

Once表示立即执行命令,并且命令执行完毕后就移除该命令的映射关系;

InSequence表示按照注册的前后顺序来调用命令;

InParallel表示平行执行命令,即不关系命令的前后调用顺序。

框架学习笔记:深度解析StrangeIoC内部运行机制的更多相关文章

  1. VC学习笔记: 1. Window程序内部运行机制

    0. 内容结构 API与SDK 窗口与句柄 消息与消息队列 WinMain函数 1. API与SDK 这里 API是指由Windows操作系统提供给应用程序的编程接口: Windows系统提供的API ...

  2. 源码深度解析SpringMvc请求运行机制(转)

    源码深度解析SpringMvc请求运行机制 本文依赖的是springmvc4.0.5.RELEASE,通过源码深度解析了解springMvc的请求运行机制.通过源码我们可以知道从客户端发送一个URL请 ...

  3. <转>ASP.NET学习笔记之理解MVC底层运行机制

    ASP.NET MVC架构与实战系列之一:理解MVC底层运行机制 今天,我将开启一个崭新的话题:ASP.NET MVC框架的探讨.首先,我们回顾一下ASP.NET Web Form技术与ASP.NET ...

  4. 《Java疯狂讲义》(第3版)学习笔记 2 - Java语言的运行机制

    内容 1.高级语言的运行机制 2.Java 语言的运行机制 1.高级语言的运行机制 高级语言主要分为编译型语言和解释型语言两类. 编译型语言是指使用专门的编译器.针对特定平台(操作系统)将高级语言源代 ...

  5. Python学习笔记之二——Python的运行机制,一般人肯定不会

    前言本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理.作者:XX   Python解释器简介   解释器是一种让其他程序运行起来的程 ...

  6. JAVA学习笔记系列2-Java程序的运行机制

    计算机高级语言的类型主要有编译型和解释型两种,而java语言是两种类型的结合. java首先利用文本编辑器编写java源程序,源文件后缀名为.java,再利用编译器(javac)将源程序编译成字节码文 ...

  7. j2ee开发之Spring2.5框架学习笔记

    Spring 2.5框架学习笔记 1.是一个开源的控制反转IOC和面向切面AOP的容器框架 2.IOC控制反转 public class PersonServiceBean { private Per ...

  8. JavaSE中线程与并行API框架学习笔记——线程为什么会不安全?

    前言:休整一个多月之后,终于开始投简历了.这段时间休息了一阵子,又病了几天,真正用来复习准备的时间其实并不多.说实话,心里不是非常有底气. 这可能是学生时代遗留的思维惯性--总想着做好万全准备才去做事 ...

  9. phalcon(费尔康)框架学习笔记

    phalcon(费尔康)框架学习笔记 http://www.qixing318.com/article/phalcon-framework-to-study-notes.html 目录结构   pha ...

随机推荐

  1. iOS开发:iOS的整体架构以及API介绍

    iOS的整体架构分为4层——Cocoa Touch层.Media层.Core Services层和Core OS层,下面概要介绍一下这4层. Cocoa Touch:构建iOS应用的一些基本系统服务, ...

  2. virtualbox更新完之后重启不成功

    前几天更新完virtualbox,一直没用,今天想用,可是提示can't not access the kernel drivers,百度完之后按照别人博客所教方法弄好了,特地来转载他人文章,表达对博 ...

  3. LeetCode: Next Permutation & Permutations1,2

    Title: Implement next permutation, which rearranges numbers into the lexicographically next greater ...

  4. 图文详解YUV420数据格式

    YUV格式有两大类:planar和packed.对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V.对于packed的YUV格式,每个像素点的Y,U ...

  5. Android下fragment切换的动画效果

    网上看到的例子,转过来记录一下,学习一下,感谢原作者的辛勤编码,效果非常好 基于Android3.0新增的动画api,效果很赞 共21种动画效果: <item>X轴缩放</item& ...

  6. TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute

    1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议,它不保证数据被送达,那么,自然的,保证数据送达的工作应该由其他的模块来完成.其中一个重要的模块就是ICMP(网络控制报文)协议. 当传送 ...

  7. [Everyday Mathematics]20150121

    设 $f\in C[0,1]$ 适合 $$\bex xf(y)+yf(x)\leq 1,\quad\forall\ x,y\in [0,1]. \eex$$ 试证: $$\bex \int_0^1 f ...

  8. java web 学习九(通过servlet生成验证码图片)

    一.BufferedImage类介绍 生成验证码图片主要用到了一个BufferedImage类,如下:

  9. Bigger is Better

    题意: 有n个火柴棒,已知拼成9个数字花费的数目,求能拼出的能整除m的最大数 分析: dp[i][j]表示,用i个火柴棒,拼出的数余m余数为j时的最大数 int tmp=dp[i][j]*10+k;( ...

  10. mysql EF

    使用 mysql-installer-community-5.6.26.0.msi visual studio 2013 update 4版 Install-Package EntityFramewo ...