zoukankan      html  css  js  c++  java
  • .NET中使用unity实现aop

    Unity是一款知名的依赖注入容器,其支持通过自定义扩展来扩充功能。在Unity软件包内默认包含了一个对象拦截(Interception)扩展定义。本篇文章将介绍如何使用对象拦截功能来帮助你分离横切关注点(Separation of cross-cutting concerns)。

    对象拦截简介

    对象拦截是一种AOP(Aspect-oriented programming)编程的实践方法。其可帮助你保持业务类的纯净,而无需考虑诸如日志和缓存等外围关注点。

    在.NET中,实现AOP有多种方法。一种方式是采用编译后处理方式,例如PostSharp。在编译后,PostSharp通过修改IL代码来诸如横切代码。

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

    • 透明代理拦截器:需要定义接口,或者要求类继承自MarshalByRefObject。
    • 接口拦截器:需要定义接口。
    • 虚方法拦截器:仅需要方法被定义成virtual方法。

    对象拦截如何工作

    当从Unity容器请求目标对象时,将不会获取到已配置的类的实例。实际上,将得到一个动态生成的代理对象,或者一个衍生类。

    如果调用代理对象的一个方法,将可以在被调用方法执行前或执行后执行一些额外行为的代码。那些定义行为的类需要实现ICallHandler接口。通过这些行为定义,我们可以访问方法调用的参数列表,可以吞噬异常,或者可以返回自定义的异常。

    附带提一下,在不使用Unity容器的条件下,也是可以使用Unity拦截器的。

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

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

    • LoggerCallHandler:将方法调用参数列表记录到日志中。
    • ExceptionLoggerCallHandler:将方法调用参数列表和异常信息及调用栈记录到日志中。

    ExceptionLoggerCallHandler定义如下:

    复制代码
     1   internal class ExceptionLoggerCallHandler : ICallHandler
     2   {
     3     public IMethodReturn Invoke(
     4       IMethodInvocation input, GetNextHandlerDelegate getNext)
     5     {
     6       IMethodReturn result = getNext()(input, getNext);
     7       if (result.Exception != null)
     8       {
     9         Console.WriteLine("ExceptionLoggerCallHandler:");
    10         Console.WriteLine("	Parameters:");
    11         for (int i = 0; i < input.Arguments.Count; i++)
    12         {
    13           var parameter = input.Arguments[i];
    14           Console.WriteLine(
    15             string.Format("		Param{0} -> {1}", i, parameter.ToString()));
    16         }
    17         Console.WriteLine();
    18         Console.WriteLine("Exception occured: ");
    19         Console.WriteLine(
    20           string.Format("	Exception -> {0}", result.Exception.Message));
    21 
    22         Console.WriteLine();
    23         Console.WriteLine("StackTrace:");
    24         Console.WriteLine(Environment.StackTrace);
    25       }
    26 
    27       return result;
    28     }
    29 
    30     public int Order { get; set; }
    31   }
    复制代码

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

    复制代码
    1   internal class ExceptionLoggerAttribute : HandlerAttribute
    2   {
    3     public override ICallHandler CreateHandler(IUnityContainer container)
    4     {
    5       return new ExceptionLoggerCallHandler();
    6     }
    7   }
    复制代码

    在这个示例中,我们创建一个简单的计算器类。同时为了使用接口拦截功能,我们还需创建一个接口类型,这样才能应用指定的行为:

    复制代码
    1   public interface ICalculator
    2   {
    3     [Logger]
    4     int Add(int first, int second);
    5 
    6     [ExceptionLogger]
    7     int Multiply(int first, int second);
    8   }
    复制代码

    计算器类的实现还和常规的一样。现在我们需要配置Unity容器:

    复制代码
     1       IUnityContainer container = new UnityContainer();
     2       container.AddNewExtension<Interception>();
     3       container
     4         .RegisterType<ICalculator, Calculator>()
     5         .Configure<Interception>()
     6         .SetInterceptorFor<ICalculator>(new InterfaceInterceptor());
     7 
     8       // Resolve
     9       ICalculator calc = container.Resolve<ICalculator>();
    10 
    11       // Call method
    12       calc.Add(1, 2);
    复制代码

    当在容器上通过调用Resolve方法来尝试获得一个Calculate类的实例时,将会得到一个代理类实例。它的名字可能类似于 ‘DynamicModule.ns.Wrapped_ICalculator_83093f794c8d452e8af4524873a017de’。当调用此包装类的某个方法时,CallHandlers将会被执行。

    总结

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

  • 相关阅读:
    Java高并发17-LongAccumulator类详解
    Java高并发16-LongAdder类源码解析(下)
    SpringBoot之模板引擎
    SpringBoot之yml与properties配置文件格式的区别
    SpringBoot之SpringBoot整合静态资源访问
    SpringBoot之SpringBoot的启动方式
    SpringBoot之RestController注解
    SpringBoot之SpringBoot依赖引入
    SpringBoot之SpringBoot与SpringCloud之间的区别
    SpringBoot之IDEA创建SpringBoot项目
  • 原文地址:https://www.cnblogs.com/cuihongyu3503319/p/8745752.html
Copyright © 2011-2022 走看看