AOP框架Dora.Interception 3.0 [2]: 实现原理

和所有的AOP框架一样,我们必须将正常的方法调用进行拦截,才能将应用到当前方法上的所有拦截器纳入当前调用链。Dora.Interception采用IL Eimit的方式实现对方法调用的拦截,接下来我们就来聊聊大致的实现原理。

一、与依赖注入框架的无缝集成

由于Dora.Interception是为.NET Core定制的AOP框架,而依赖注入是.NET Core基本的编程方式,所以Dora.Interception最初就是作为一个依赖注入框架的扩展而涉及的。我们知道.NET Core的依赖注入框架支持三种服务实例提供方式。由于Dora.Interception最终会利用IL Emit的方式动态生成目标实例的类型,所以它只适合第一种服务注册方式

如果注册的是一个服务类型,最终会选择一个匹配的构造函数来创建服务实例;

如果注册的是一个服务实例创建工厂,那么目标服务实例就由该工厂来创建;

如果注册的是一个服务实例,那么它会直接作为目标服务实例。

二、两种拦截方式

.NET Core的依赖注入框架采用ServiceDescriptor对象来描述服务注册。拦截器最终会注册到ImplementationType 属性表示的实现类型上,所以Dora.Interception需要根据该类型生成一个可以被拦截的代理类型。针对ServiceType属性表示的服务类型的不同,我们会采用不同的代码生成方式。

针对接口

如果注册服务时提供的是一个接口和它的实现类型,我们会按照如下的方式来生成可被拦截的代理类型。假设接口和实现类型分别为IFoobar和Foobar,那么我们会生成一个同样实现IFoobar接口的FoobarProxy类型。FoobarProxy对象是对Foobar对象的封装,对于它实现的方法来说,如果没有拦截器应用到Foobar类型对应的方法上,它只需要调用封装的这个Foobar对象对应的方法就可以了。反之,针对拦截器的调用将会注入到FoobarProxy实现的方法中。

image_thumb2_thumb

针对类型

如果注册是提供的服务类型并不是一个接口,而是一个类型,比如服务类型和实现类型都是Foobar,上述的代码生成机制就不适用了。此时我们要求Foobar必须是一个非封闭(Sealed)的类型,而且拦截器只能应用到它的虚方法上。基于这种假设,我们生成的代理类型FoobarProxy实际上市Foobar的子类,如果拦截器应用到Foobar的某个虚方法上,FoobarProxy只需要重写这个方法将应用的拦截器注入到方法调用管道中。

image_thumb5_thumb

三、ICodeGenerator & ICodeGeneratorFactory

上述针对IL Emit的动态代理类型生成体现在如下这个ICodeGenerator接口上,该接口唯一的方法GenerateInterceptableProxyClass会根据提供的上下文信息生成可被拦截的代理类型。作为代码生成上下文的的CodeGenerationContext对象来说,它除了提供服务注册的类型和实现类型之外,它还提供了IInterceptorRegistry对象。

 

public interface ICodeGenerator { Type GenerateInterceptableProxyClass(CodeGenerationContext context); } public class CodeGenerationContext { public Type InterfaceOrBaseType { get; } public Type TargetType { get; } public IInterceptorRegistry Interceptors { get; } public CodeGenerationContext(Type baseType, IInterceptorRegistry interceptors ); public CodeGenerationContext(Type @interface, Type targetType, IInterceptorRegistry interceptors); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgywsj.html