使用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("\tParameters:");
11         for (int i = 0; i < input.Arguments.Count; i++)
12         {
13           var parameter = input.Arguments[i];
14           Console.WriteLine(
15             string.Format("\t\tParam{0} -> {1}", i, parameter.ToString()));
16         }
17         Console.WriteLine();
18         Console.WriteLine("Exception occured: ");
19         Console.WriteLine(
20           string.Format("\tException -> {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需求已经足够了。

代码下载

文章译自

 

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
缓存 Java Sentinel
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
1133 3
|
缓存 安全 Java
Spring高手之路21——深入剖析Spring AOP代理对象的创建
本文详细介绍了Spring AOP代理对象的创建过程,分为三个核心步骤:判断是否增强、匹配增强器和创建代理对象。通过源码分析和时序图展示,深入剖析了Spring AOP的工作原理,帮助读者全面理解Spring AOP代理对象的生成机制及其实现细节。
939 0
Spring高手之路21——深入剖析Spring AOP代理对象的创建
|
Java 测试技术 开发者
【亮剑】通过自定义注解实现Spring AOP,可以更灵活地控制方法拦截和增强
【4月更文挑战第30天】通过自定义注解实现Spring AOP,可以更灵活地控制方法拦截和增强。首先定义自定义注解,如`@MyCustomAnnotation`,然后创建切面类`MyCustomAspect`,使用`@Pointcut`和`@Before/@After`定义切点及通知。配置AOP代理,添加`@EnableAspectJAutoProxy`到配置类。最后,在需拦截的方法上应用自定义注解。遵循保持注解职责单一、选择合适保留策略等最佳实践,提高代码可重用性和可维护性。记得测试AOP逻辑。
619 1
|
容器
springboot-自定义注解拦截ip aop和ioc
springboot-自定义注解拦截ip aop和ioc
|
存储 图形学
【unity小技巧】unity事件系统创建通用的对象交互的功能
【unity小技巧】unity事件系统创建通用的对象交互的功能
667 0
|
设计模式 算法 Java
AOP跨模块捕获异常遭CGLIB拦截而继续向上抛出异常
最近,在开发过程中,我遇到一个不易察觉的小bug。这个bug并没有直接给出报错信息,使得排查问题的根源变得困难。我希望通过分享这个经验,帮助大家避免重蹈覆辙,以免浪费不必要的时间和精力。为了避免类似的困境,我们应当时刻保持警惕,对开发过程中的每一个细节都进行严格的检查。同时,利用调试工具和日志输出等功能,可以帮助我们更快速地定位和解决问题。此外,定期进行代码审查和测试也是非常必要的,这有助于发现潜在的问题并及时解决。
333 1
|
API 图形学
Unity Hololens2开发|(十)MRTK3空间操作 ObjectManipulator (对象操控器)
Unity Hololens2开发|(十)MRTK3空间操作 ObjectManipulator (对象操控器)
|
C# 图形学
【Unity 3D】游戏对象、添加删除获取组件、预制体Prefabs简介
【Unity 3D】游戏对象、添加删除获取组件、预制体Prefabs简介
582 0
|
缓存 Java Spring
Spring AOP中CGLIB代理对象增强通知执行原理
Spring AOP中CGLIB代理对象增强通知执行原理
289 0

热门文章

最新文章