动态代理
反射机制:程序运行时自省的能力,通过反射操作类与对象,获取对象的类定义,类声明的属性与方法,调用方法与构造对象,甚至在运行时修改类的定义。
动态代理:是一种方便运行时动态构建代理,动态处理代理方法调用机制。代理是对调用目标的一个包装,对目标代码不是直接发生,而是通过代理发生,
动态代理,很多情况可以看作是装饰器的一个运用,反射是实现的一种常用的方式。
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<Calculater>() .As<ICalculater>() .EnableInterfaceInterceptors() .InterceptedBy(typeof(CalculaterInterceptor), typeof(CalculaterInterceptor2)); // 这里定义了两个拦截器,注意它们的顺序 builder.RegisterType<CalculaterInterceptor>(); // 注册拦截器 builder.RegisterType<CalculaterInterceptor2>(); // 注册拦截器2 var ioc = builder.Build(); var calculater = ioc.Resolve<ICalculater>(); var addResult = calculater.Add(2, 3); Console.WriteLine($"add result: {addResult}");
另外:接口上以特性的形式注册,如上面代码中注释掉的那部分。若是既有在类型上注册,也有在 Autofac 的 Builder 中注册,那么这个拦截器会重复执行。
非虚方法,所有拦截器不会在该方法中调用。
在ABP vnext的实现方式,在服务自动注册模块,首先根据 实现类型ImplementationType(是class,不是接口,抽象类,泛型类),检查生命周期、servicesType注册在SerivceCollection里面,OnExposing定义ImplementationType的ExposedTypes,,可自定义委托函数OnRegistred,定义ImplementationType的Interceptors、
在注入Autofac容器
AbpAsyncDeterminationInterceptor<>的泛型参数才是用户定义的拦截器, interceptor:IAbpIntercepor
if (serviceType.IsInterface) { registrationBuilder = registrationBuilder.EnableInterfaceInterceptors(); } else { (registrationBuilder as IRegistrationBuilder<TLimit, ConcreteReflectionActivatorData, TRegistrationStyle>)?.EnableClassInterceptors(); } foreach (var interceptor in interceptors) { registrationBuilder.InterceptedBy( typeof(AbpAsyncDeterminationInterceptor<>).MakeGenericType(interceptor) ); }
AsyncDeterminationInterceptor(IAsyncInterceptor)
CastleAsyncAbpInterceptorAdapter<TInterceptor>(TInterceptor)需要用户定义的拦截器,的泛型参数, TInterceptor : IAbpInterceptor
这里有个IAbpMethodInvocation的实现CastleAbpMethodInvocationAdapter(invocation, proceedInfo, proceed),CastleAbpMethodInvocationAdapterWithReturnValue
https://github.com/JSkimming/Castle.Core.AsyncInterceptor
关于特性
1、Dependency特性,它拥有ServiceLifeTime,TryRegister,ReplaceServices属性
ExploseService特性,同时实现IExplosedServiceTypesProvider对外暴露的ServiceTypes类型,是对包括InclueDefault(即包括默认接口,I开头,默认结尾)IncludeSelf( 包括自己)
type.GetCustomAttribute<DependencyAttribute>(true); private static readonly ExposeServicesAttribute DefaultExposeServicesAttribute = new ExposeServicesAttribute { IncludeDefaults = true, IncludeSelf = true }; public static List<Type> GetExposedServices(Type type) { return type .GetCustomAttributes() .OfType<IExposedServiceTypesProvider>() .DefaultIfEmpty(DefaultExposeServicesAttribute) .SelectMany(p => p.GetExposedServiceTypes(type)) .ToList(); }
public static List<Type> FindDependedModuleTypes(Type moduleType) { AbpModule.CheckAbpModuleType(moduleType); var dependencies = new List<Type>(); var dependencyDescriptors = moduleType .GetCustomAttributes() .OfType<IDependedTypesProvider>(); foreach (var descriptor in dependencyDescriptors) { foreach (var dependedModuleType in descriptor.GetDependedTypes()) { dependencies.AddIfNotContains(dependedModuleType); } } return dependencies; }
public static UnitOfWorkAttribute GetUnitOfWorkAttributeOrNull(getmethodInfo) { var attrs = methodInfo.GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray(); if (attrs.Length > 0) { return attrs[0]; } attrs = methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(true).OfType<UnitOfWorkAttribute>().ToArray(); if (attrs.Length > 0) { return attrs[0]; } return null; } private static bool AnyMethodHasUnitOfWorkAttribute(TypeInfo implementationType) { return implementationType .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Any(HasUnitOfWorkAttribute); } private static bool HasUnitOfWorkAttribute(MemberInfo methodInfo) { return methodInfo.IsDefined(typeof(UnitOfWorkAttribute), true); }