反射机制:程序运行时自省的能力,通过反射操作类与对象,获取对象的类定义,类声明的属性与方法,调用方法与构造对象,甚至在运行时修改类的定义。
动态代理:是一种方便运行时动态构建代理,动态处理代理方法调用机制。代理是对调用目标的一个包装,对目标代码不是直接发生,而是通过代理发生,
动态代理,很多情况可以看作是装饰器的一个运用,反射是实现的一种常用的方式。
Autofac与Castle.DynamicProxy实现AOP功能
1、定义拦截器,实现 Castle.DynamicProxy.IInterceptor
public interface IInterceptor { void Intercept(IInvocation invocation); }
其中:IInvocation的接口的方法,invocation.Arguments是数组,args[0]是第一个参数
invocation.Proceed(); // 调用下一个拦截器,直到最终的目标方法。
定义好了拦截器后,如何应用到相关对象呢?有两种方式:
在注册对象的同时启用 EnableClassInterceptors() 方法。
比如:注册两个拦截器,然后通过autofac 的Ioc容器,实现Resolve服务,执行顺序:CalculaterInterceptor --> CalculaterInterceptor2 --> Target Method --> CalculaterInterceptor2 --> CalculaterInterceptor 。拦截器中 invocation.Proceed() 方法用于调用下一个拦截器(若存在),直到最终的目标方法(Target Method)。不过 invocation.Proceed() 并不是一定要调用的,例如,对于有返回值的目标方法,我们在拦截器中设置 invocation.ReturnValue 值就可正确执行,这样便不会执行目标方法。在有些场景中,如身份验证、缓存读取等还是特别有用
var builder = new ContainerBuilder(); builder.RegisterType() .As () .EnableInterfaceInterceptors() .InterceptedBy(typeof(CalculaterInterceptor), typeof(CalculaterInterceptor2)); // 这里定义了两个拦截器,注意它们的顺序 builder.RegisterType (); // 注册拦截器 builder.RegisterType (); // 注册拦截器2 var ioc = builder.Build(); var calculater = ioc.Resolve (); var addResult = calculater.Add(2, 3); Console.WriteLine($"add result: {addResult}");
另外:接口上以特性的形式注册,如上面代码中注释掉的那部分。若是既有在类型上注册,也有在 Autofac 的 Builder 中注册,那么这个拦截器会重复执行。
非虚方法,所有拦截器不会在该方法中调用。
在ABP vnext的实现方式,其中CastleAbpInterceptorAdapter<>的泛型参数才是用户定义的拦截器
if (serviceType.IsInterface) { registrationBuilder = registrationBuilder.EnableInterfaceInterceptors(); } else { (registrationBuilder as IRegistrationBuilder)?.EnableClassInterceptors(); } foreach (var interceptor in interceptors) { registrationBuilder.InterceptedBy( typeof(CastleAbpInterceptorAdapter<>).MakeGenericType(interceptor) ); } return registrationBuilder;
IInterceptor的实现是CastleAbpInterceptorAdapter的适配器,在此方法没有看到invocation.Proceed() 方法,而且这个方法需要用户定义的拦截器,恰是适配器的泛型参数,委托给他
public void Intercept(IInvocation invocation) { var proceedInfo = invocation.CaptureProceedInfo(); var method = invocation.MethodInvocationTarget ?? invocation.Method; if (method.IsAsync()) { InterceptAsyncMethod(invocation, proceedInfo); } else { InterceptSyncMethod(invocation, proceedInfo); } }
拦截器有无返回值
private async Task ExecuteWithoutReturnValueAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo) { await Task.Yield(); await _abpInterceptor.InterceptAsync( new CastleAbpMethodInvocationAdapter(invocation, proceedInfo) ); } private async TaskExecuteWithReturnValueAsync (IInvocation invocation, IInvocationProceedInfo proceedInfo) { await Task.Yield(); await _abpInterceptor.InterceptAsync( new CastleAbpMethodInvocationAdapter(invocation, proceedInfo) ); return await (Task )invocation.ReturnValue; }
这里有个IAbpMethodInvocation的实现CastleAbpMethodInvocationAdapter,如何官方的实现的InvocationInvocation进行无缝结果,实现有什么差别ProceedInfo.Invoke()应该是调用目标的方法
在Castle.Core/DynamicProxy/AbstractInvocation.cs的Proceed()有InvokeMethodOnTarget()方法。
public void Proceed() { ProceedInfo.Invoke(); if (Invocation.Method.IsAsync()) { AsyncHelper.RunSync(() => (Task)Invocation.ReturnValue); } } public Task ProceedAsync() { ProceedInfo.Invoke(); _actualReturnValue = Invocation.ReturnValue; return Invocation.Method.IsAsync() ? (Task)_actualReturnValue : Task.FromResult(_actualReturnValue); }
问题:如何写这个适配器,原理是什么,作用是什么,如何解决异步的问题,这是一个很值得学习的地方