以前作AgentBooking时候,遇到两个问题比较棘手,一个是异常的传递与捕获:如何能够合理地在层层代码调用中统一传递并统一捕获异常。由于若是有一个作法,能够地方统一处理异常,可使代码减小不少try cath逻辑,也不一样时刻关注该怎么抛异常,这样代码写起来就比较happy。
第二个是Log的统一记录。和第一个问题同样,若是能够找到一种方法,能够统一记Log,不用再在代码中时刻关注何时该怎么记Log,这确定是一种更好的改进。
上两个星期去Search了一下AOP(
面向切面编程),其思想很大程度上能够给咱们提供帮助。AOP大概意思就是说,在代码的编译期或者运行期自动为程序插入额外的功能逻辑。其思想就是将主要业务逻辑和辅助功能分离出来。在MOE中有一个经典的应用场合:每次MOE在调用Web Service时候,都回家RQ序列号并保存到一个txt的Log文件中,因此这个调用webservice的方法既有主要业务逻辑(RQ的生成)的代码,又有RQ入Log的辅助功能。若是应用AOP,则这个方法中只须要写主要业务的逻辑,RQ入LOG的逻辑代码能够交给AOP框架自动在编译期动态(或静态)“插入”到原来的代码里面。
AOP实现手段大概有两种,一是在编译是对代码的IL进行分析,而后插入(官方叫“织入”)额外功能的代码。二是对方法调用进行拦截并执行额外代码逻辑。
这里主要介绍一下context与方法拦截。(由于IL涉及到编译器,太深奥,不明觉厉,而方法拦截除了AOP,感受还能够用在其余地方)
在.NET中,每一个App Domain(应用程序域,在.net中一个进程能够有N个线程,一个线程能够有N个App Domain)都至少有一个Context,当一个对象被new出来后,就是存在于context中。(我以为context是更是一种编程思想,就是将资源都放在一个地方。典型的有HttpContext,就集中包含了每一个HttpRequest访问时的一些信息)。.net程序第一个context是一个默认context,每一个context都有一个ContextID.能够经过Thread.CurrentContext来访问当前Context。
.net里的对象从context的角度能够分为两种:context-aglie object(上下文灵活对象)和context-bound object(上下文绑定对象)。
context-aglie object老是存在于这个对象的调用者所在的context中(我查了一下资料,大概是这个意思,但我尚未验证过是否是这样)。对context-aglie object的调用是一种直觉引用,并非经过代理的调用。这个很重要,由于直接的调用是不能被拦截的,只有经过“代理”的调用才能被拦截,见下文。
而另外一种是context-bound object(上下文绑定对象)。若是一个对象继承了ContextBoundObject ,就成了一个context-bound object。 context-bound object会被强制绑定到一个指定的context中。当一个调用者和被调用的对象处于不一样的context中时,这个调用不是直接的引用,而是须要经过代理去进行的。正是由于有这个“代理”,才能在调用过程当中作手脚,例如在调用这个对象的一个方法前或调用方法完毕后作一些额外的逻辑(如Log,或者方法执行的时间统计等等),听起来很熟悉?在HttpModule中也是这种作法。
这里的“代理”有几种:远程代理(Remote Proxy),虚拟代理(Virtual Proxy),智能引用代理(Smart Reference Proxy).在.NET Remoting中,代理又分为透明代理(Transparent Proxy)和真实代理(Real Proxy)
方法调用的拦截就须要用到透明代理和真实代理。当一个对象调用另外一个context里的对象(好比说调用该对象的某个方法),这个调用到达透明代理时会被转换为一个Message,并将Message传给Real Proxy。Real Proxy将Message传到这个对象的过程当中,Message会经历由N个MessageSink(消息槽)组成的管道中。每一个MessageSink能够对消息进行处理并再次抛给下一个MessageSink,一直将调用传递到那个Object为止。每一个MessageSink中即是咱们拦截方法调用的地方了。