AOP---Unity使用初探
.Net下面实现依赖注入的框架有很多,如Spring.Net等等。微软也有自己的工具---Unity。作为企业库的一部分,Unity实现依赖注入也成为学习企业库比较重要的一环。微软给出的说法是【它是一个轻量级的、可扩展的依赖注入容器】。
对Unity高级用法,我还不是很熟悉,一下就简单说说它的初级用法,给初学者扫扫盲,高手就可以直接跳过了。如果我理解有误,还希望大鸟们不理赐教。
首先介绍一下开发环境:Visio Studio2008 Team,SP1、企业库版本5.0。
提到Unity,就不能不说UnityContainer。UnityContainer是Unity中最基础的类,它是实现依赖注入的基础。 这里我只给出一种最基本的拦截方式------UnityContainer对象中RegisterType、Resolve实现。RegisterType从函数名上理解就是注册类型之间的关系。Resolve:通过UnityContainer对象获取注册的对象。被拦截的对象需要实现IInterceptionBehavior接口。
总体上,实现拦截有两个步骤:
1、注册被拦截对象
2、获取被拦截对象的实例。
当然,以上两步都是通过UnityContainer来实现的。也可以通过配置的方式来实现。这里先熟悉一下通过编程的方式来进行配置的应用,通过配置的方式实现,留待之后介绍构造函数注入、属性、方法注入的时候再进行介绍。
先简要介绍一下本节示例中类、接口之间的关系。人员接口IPerson、学生类Student,Student实现IPerson。我们需要拦截Student类中实现的IPerson接口中的方法【一个为虚方法、一个为实例方法】并在拦截的所执行的目标方法执行进行一些输出操作。实现拦截得到类ILogInterception、ILogInterception1,需要实现企业库接口-----IInterceptionBehavior。代码如下:
public interface IPerson { string Name { get; set; } int Age { get; set; } void Speek(); void Run(int speed); } public class Student : IPerson { public string Name { get; set; } public int Age { get; set; } public virtual void Speek() { Name = "tesetName"; Age = 29; Console.WriteLine("Person Speeks"); } public void Run(int speed) { Console.WriteLine(string.Format("Student Runs... at speed {0}", speed)); } } public class LogInterception : IInterceptionBehavior { private static readonly MethodInfo methodInfo = typeof(Student).GetMethod("Speek"); public IEnumerable<Type> GetRequiredInterfaces() { return new[] { typeof(IPerson) }; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("开始拦截"); if (input == null) { throw new Exception("参数不能为null"); } if (getNext == null) { throw new Exception("委托不能为null"); } if (input.MethodBase == methodInfo) { Console.WriteLine("开始执行目标方法"); return getNext()(input, getNext); } else { return input.CreateMethodReturn(null); } } public bool WillExecute { get { return true; } } } public class ILogInterception1 : IInterceptionBehavior { private static readonly MethodInfo methodInfo = typeof(IPerson).GetMethod("Run"); public bool WillExecute { get { return true; } } public IEnumerable<Type> GetRequiredInterfaces() { return new[] { typeof(IPerson) }; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("开始拦截"); if (input == null) { throw new Exception("参数不能为空"); } if (getNext == null) { throw new Exception("委托没有被实例化"); } if (input.MethodBase == methodInfo) { Console.WriteLine("即将执行目标方法"); Console.WriteLine(string.Format("目标方法参数个数为:{0}",input.Arguments.Count)); if (input.Arguments.Count > 0) { Console.WriteLine(string.Format("实际参数为:{0}", input.Arguments[0])); } InvokeInterceptionBehaviorDelegate tempDelegate = getNext(); return tempDelegate(input, getNext); } else { return input.CreateMethodReturn(null); } } }
在拦截虚方法的使用代码如下:
container.AddNewExtension<Interception>(); container.RegisterType<Student>( new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<LogInterception>(), new AdditionalInterface<IPerson>()); var studentInfo = container.Resolve<Student>(); studentInfo.Speek();
输出如下图:
由以上输出结果可知:studentInfo在调用Speek方法时,首先不是直接去调用Student类的Speed方法,而是执行了LogInterception类中的Invoke方法。在Invoke方法getNext()(input, getNext)中,才真正调用了Student类的Speed方法。这就是我们所说的拦截。
以上是对接口中的虚方法中的拦截方式。对实例方法的拦截方式和上述拦截又有所不同。实例方法的拦截方式如下:
container.AddNewExtension<Interception>(); container.RegisterType<IPerson,Student>( new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<ILogInterception1>() ); var student = container.Resolve<IPerson>(); student.Run(100);
输出如下图:
注意:拦截虚方法和拦截实例方式的方式是不一样的。如果用拦截实例的方式来拦截虚方法或者用拦截虚方法的方式来拦截实例方法,则不会有对我们需要进行拦截的方法进行拦截。
此外,一种写法在我看拦截的时候有点费解,就是getNext()(input, getNext);因为在我们的编程习惯里,什么时候会有一个方法会有这种调用方式呢。?这里就需要好好考虑考虑了。getNext只是一个简单的方法签名吗。?实际上它是GetNextInterceptionBehaviorDelegate类型的。从其名字上看便可知它是一个委托类型,可是委托也没有像这样使用的。再看看GetNextInterceptionBehaviorDelegate的定义:
public delegate InvokeInterceptionBehaviorDelegate GetNextInterceptionBehaviorDelegate();
从GetNextInterceptionBehaviorDelegate的签名便知道它的返回值InvokeInterceptionBehaviorDelegate应该也是一种委托类型的,如果是这样那也不足为怪了。验证一下这个想法,看看InvokeInterceptionBehaviorDelegate的定义:
public delegate IMethodReturn InvokeInterceptionBehaviorDelegate(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext);
确实,它是一个需要IMethodInvocation、与GetNextInterceptionBehaviorDelegate类型的委托。