Unity 是一款知名的依赖注入容器( dependency injection container) ,其支持通过自定义扩展来扩充功能。

在Unity软件包内 默认包含了一个对象拦截(Interception)扩展定义。

本篇文章将介绍如何使用对象拦截(Interception)来分离横切关注点(Separation of cross-cutting concerns)。

对象拦截简介

对象拦截(Interception)是一种 AOP(Aspect-oriented programming)编程的实践方法。

其可帮助你保持业务类的纯净,而无需考虑诸如日志和缓存等外围关注点(other concerns)。

在.NET中,实现AOP有多种方法。

一种方式是采用编译后( post-compiler)处理方式,例如 PostSharp。在编译后( after compilation),PostSharp通过修改IL代码来注入(injects)横切代码。

相反地,对象拦截(Interception)是在运行时(Runtime)执行的,同时也意味着会有一些限制。依据不同的拦截器实现,会有如下这些约束:

  • 透明代理拦截器(Transparent Proxy Interceptor):需要定义接口(interface),或者要求类继承(inherit)自MarshalByRefObject。
  • 接口拦截器(Interface Interceptor):需要定义接口。
  • 虚方法拦截器(Virtual Method Interceptor):仅需要方法被定义成virtual方法。

对象拦截如何工作

当从Unity容器请求目标对象时,将不会获取到已配置的类的实例。

实际上,将得到一个动态生成的代理对象(dynamically generated proxy object),或者一个衍生类(derived class)。

如果调用代理对象的一个方法,将可以在被调用方法执行前或执行后执行一些额外行为的代码。

那些定义行为的类需要实现ICallHandler接口。

通过这些行为定义,我们可以访问方法调用的参数列表(arguments),可以吞噬异常(swallow exceptions),或者返回自定义的异常( return custom exceptions)。

  附带提一下,在不使用 Unity container的条件下,也是可以使用 Unity interception的。

示例:将异常和方法调用参数列表记录到日志中

在下面的示例中,我们将创建两个自定义的行为(behaviors),都实现了ICallHandler接口:

  • LoggerCallHandler:将方法调用参数列表(method arguments)记录到日志中。
  • ExceptionLoggerCallHandler:当发生异常时,将方法调用参数列表和调用栈信息记录到日志中。

ExceptionLoggerCallHandler定义如下:

internal class ExceptionLoggerCallHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
// before invoking the method on the original target
Console.WriteLine(String.Format("Invoking method {0} at {1} ", input.MethodBase, DateTime.Now.ToString() )); // invoke the next behavior in the chain
IMethodReturn result = getNext()(input, getNext); // after invoking the method on the original target
if (result.Exception != null)
{
Console.WriteLine("Exception occured: " + result.Exception.Message); Console.WriteLine("Parameters:");
foreach (var parameter in input.Arguments)
{
Console.WriteLine(parameter.ToString());
} Console.WriteLine("StackTrace:");
Console.WriteLine(Environment.StackTrace);
} return result;
} public int Order { get; set; }
}

为了将行为应用到方法上,我们需要创建相应的HandlerAttribute来创建行为的实例。

internal class ExceptionLoggerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new ExceptionLoggerCallHandler();
}
}

在这个示例中,我们创建一个简单的计算器类。

同时为了使用接口拦截( Interface Interception),我们还需创建一个接口类型,这样才能应用指定的行为:

public interface ICalculator
{
[Logger]
int Add(int first, int second); [ExceptionLogger]
int Multiply(int first, int second);
}

计算器类的实现还和常规的一样。

现在我们需要配置(setup)Unity容器:

IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<ICalculator, Calculator>()
.Configure<Interception>()
.SetInterceptorFor<ICalculator>(new InterfaceInterceptor()); // Resolve
ICalculator calc = container.Resolve<ICalculator>(); // Call method
calc.Add(, );

当在容器上通过调用Resolve方法来尝试获得一个Calculate类的实例时,将会得到一个代理类(proxy  class)实例。

它的名字可能类似于 ‘DynamicModule.ns.Wrapped_ICalculator_83093f794c8d452e8af4524873a017de’。

当调用此包装类(the wrapper class)的某个方法时,CallHandlers将会被执行。

总结

Unity并不提供一个完整的AOP框架,因此使用它会有一些限制。但不管怎样,使用Unity对象拦截功能来实现一些基本的AOP需求已经足够了。

原文链接:AOP - Interception with Unity 2.0 (http://www.palmmedia.de/Blog/2010/9/26/aop-interception-with-unity-20)

最新文章

  1. Spring 学习笔记 3. 尚硅谷_佟刚_Spring_配置 Bean
  2. Android学习地址
  3. 在Linux CentOS上编译CoreCLR
  4. 【转】在Eclipse中建立第一个Servlet程序
  5. JDK个目录,以及与环境变量的关系
  6. iOS纯代码手动适配 分类: ios技术 2015-05-04 17:14 239人阅读 评论(0) 收藏
  7. 使用RandomAccessFile在两个java进程之间传递数据
  8. 给sftp创建新用户、默认打开和限制在某个目录
  9. vs2010等宽字体设置
  10. WebBrowser Cookie
  11. Python中的垃圾回收与del语句
  12. 按照不规则多边形shp文件分割底层栅格文件tif,统计不同栅格的属性值
  13. 816. Ambiguous Coordinates
  14. (18)jq事件操作
  15. 百度浏览器 UserAgent
  16. Oracle学习笔记:外连接(+)的用法
  17. 当Java遇到XML 的邂逅+dom4j
  18. hive之案例分析(grouping sets,lateral view explode, concat_ws)
  19. 研究jenkins集成unittest成图
  20. ios - 设置一个VC的navigationController的显示图案或文字,其他navigationController依旧不变

热门文章

  1. 网络编程OSI介绍
  2. Python包管理工具setuptools相关
  3. S07
  4. 一月七笔千万美元投资!国内VR行业在刮什么风?
  5. LeetCode 225题用队列实现栈(Implement Stack using Queues) Java语言求解
  6. Python——6切片
  7. C++扬帆远航——16(猜数字)
  8. R语言入门级实例——用igragh包分析社群
  9. [翻译]python3中新的字符串格式化方法-----f-string
  10. go语言指南之映射练习