C# 使用 Castle 实现 AOP及如何用 Autofac 集成 Castle
Castle是2003年诞生于ApacheAvalon项目,目的是为了创建一个IOC框架。发展到现在已经有四个组件:
- ORM组件:ActiveRecord
- IOC组件:Windsor
- 动态代理组件:DynamicProxy
- WebMVC组件:MonoRail
本文主要介绍动态代理组件Castle.DynamicProxy
基本用法
Castle.DynamicProxy是通过Emit反射动态生成代理类来实现的,效率相对静态植入要慢一点,但比普通的反射又高一些。动态代理只对公共接口方法、类中的虚方法生效,因为只有接口中的方法、类中的虚方法才可以在子类中重写。
基于接口的拦截器
publicinterfaceIProductRepository { voidAdd(stringname); } publicclassProductRepository:IProductRepository { publicvoidAdd(stringname)=>Console.WriteLine($"新增产品:{name}"); } publicclassLoggerInterceptor:IInterceptor { publicvoidIntercept(IInvocationinvocation) { varmethodName=invocation.Method.Name; Console.WriteLine($"{methodName}执行前"); //调用业务方法 invocation.Proceed(); Console.WriteLine($"{methodName}执行完毕"); } } classProgram { staticvoidMain(string[]args) { ProxyGeneratorgenerator=newProxyGenerator(); IInterceptorloggerIntercept=newLoggerInterceptor(); IProductRepositoryproductRepo=newProductRepository(); IProductRepositoryproxy=generator.CreateInterfaceProxyWithTarget(productRepo,loggerIntercept); proxy.Add("大米"); Console.Read(); } }
基于类的拦截器
publicclassProductRepository { publicvirtualvoidAdd(stringname)=>Console.WriteLine($"新增产品:{name}"); } staticvoidMain(string[]args) { ProxyGeneratorgenerator=newProxyGenerator(); IInterceptorloggerIntercept=newLoggerInterceptor(); ProductRepositoryproxy=generator.CreateClassProxyWithTarget(newProductRepository(),loggerIntercept); //使用CreateClassProxy泛型方法可以省去实例化代码 //ProductRepositoryproxy=generator.CreateClassProxy(loggerIntercept); proxy.Add("大米"); }
在上例中,如果ProductRepository.Add不是虚方法,也不会报错,但是拦截器不会被调用。
异步函数拦截
Castle.DynamicProxy对异步函数的拦截跟同步没啥差别,只是,如果要在方法执行完成后插入内容,需要await
publicclassProductRepository { publicvirtualTaskAdd(stringname) { returnTask.Run(()=> { Thread.Sleep(1000); Console.WriteLine($"异步新增产品:{name}"); }); } } publicclassLoggerInterceptor:IInterceptor { publicasyncvoidIntercept(IInvocationinvocation) { varmethodName=invocation.Method.Name; Console.WriteLine($"{methodName}执行前"); invocation.Proceed(); //不await的话将会先输出“执行完毕”,再输出“异步新增产品” vartask=(Task)invocation.ReturnValue; awaittask; Console.WriteLine($"{methodName}执行完毕"); } }
上面这个写法是简单粗暴的,如果碰到返回值是Task
可以使用Castle.Core.AsyncInterceptor包,它包装了Castle,使异步调用更简单。
Castle.Core.AsyncInterceptor的GitHub地址:https://github.com/JSkimming/Castle.Core.AsyncInterceptor
publicclassProductRepository:IProductRepository { publicTaskAdd(stringname) { returnTask.Run(()=> { Thread.Sleep(1000); Console.WriteLine($"异步新增产品:{name}"); }); } publicTaskGet() { returnTask.Run(()=> { Thread.Sleep(1000); Console.WriteLine($"获取产品"); return"大米"; }); } } publicclassLoggerInterceptor:IAsyncInterceptor { publicvoidInterceptAsynchronous(IInvocationinvocation) { invocation.ReturnValue=InternalInterceptAsynchronous(invocation); } asyncTaskInternalInterceptAsynchronous(IInvocationinvocation) { varmethodName=invocation.Method.Name; Console.WriteLine($"{methodName}异步执行前"); invocation.Proceed(); await(Task)invocation.ReturnValue; Console.WriteLine($"{methodName}异步执行完毕"); } publicvoidInterceptAsynchronous (IInvocationinvocation) { invocation.ReturnValue=InternalInterceptAsynchronous (invocation); Console.WriteLine(((Task )invocation.ReturnValue).Id); } privateasyncTask InternalInterceptAsynchronous (IInvocationinvocation) { varmethodName=invocation.Method.Name; Console.WriteLine($"{methodName}异步执行前"); invocation.Proceed(); vartask=(Task )invocation.ReturnValue; TResultresult=awaittask; Console.WriteLine(task.Id); Console.WriteLine($"{methodName}异步执行完毕"); returnresult; } publicvoidInterceptSynchronous(IInvocationinvocation) { varmethodName=invocation.Method.Name; Console.WriteLine($"{methodName}同步执行前"); invocation.Proceed(); Console.WriteLine($"{methodName}同步执行完毕"); } } classProgram { staticvoidMain(string[]args) { ProxyGeneratorgenerator=newProxyGenerator(); IAsyncInterceptorloggerIntercept=newLoggerInterceptor(); IProductRepositoryproductRepo=newProductRepository(); IProductRepositoryproxy=generator.CreateInterfaceProxyWithTarget(productRepo,loggerIntercept); proxy.Get(); } }
这是Castle.Core.AsyncInterceptor提供的示例写法,这里有个问题,也是我的疑惑。invocation.ReturnValue=InternalInterceptAsynchronous(invocation);将导致代理返回的Task是一个新的Task,这一点我们可以输出Task.Id来确认。个人感觉有点画蛇添足。
publicasyncvoidInterceptAsynchronous(IInvocationinvocation) { varmethodName=invocation.Method.Name; Console.WriteLine($"{methodName}异步执行前"); invocation.Proceed(); vartask=(Task )invocation.ReturnValue; awaittask; Console.WriteLine($"{methodName}异步执行完毕"); }
这样就挺好的。
如果有小伙伴知道为什么要返回一个新的Task,请留言告诉我,谢谢!
Autofac集成
Autofac.Extras.DynamicProxy是一个Autofac扩展,可与Castle一起提供AOP拦截。
基于接口的拦截器
staticvoidMain(string[]args) { ContainerBuilderbuilder=newContainerBuilder(); //注册拦截器 builder.RegisterType().AsSelf(); //注册要拦截的服务 builder.RegisterType ().AsImplementedInterfaces() .EnableInterfaceInterceptors()//启用接口拦截 .InterceptedBy(typeof(LoggerInterceptor));//指定拦截器 IContainercontainer=builder.Build(); IProductRepositoryproductRepo=container.Resolve (); productRepo.Add("大米"); }
基于类的拦截器
staticvoidMain(string[]args) { ContainerBuilderbuilder=newContainerBuilder(); //注册拦截器 builder.RegisterType().AsSelf(); //注册要拦截的服务 builder.RegisterType () .EnableClassInterceptors()//启用类拦截 .InterceptedBy(typeof(LoggerInterceptor));//指定拦截器 IContainercontainer=builder.Build(); ProductRepositoryproductRepo=container.Resolve (); productRepo.Add("大米"); }
异步函数拦截
Castle.Core.AsyncInterceptor中,IAsyncInterceptor接口并不集成IInterceptor接口,而Autofac.Extras.DynamicProxy是绑定Castle的,所以按上面同步拦截的写法是会报错的。
IAsyncInterceptor提供了ToInterceptor()扩展方法来进行类型转换。
publicclassLoggerInterceptor:IInterceptor { readonlyLoggerAsyncInterceptorinterceptor; publicLoggerInterceptor(LoggerAsyncInterceptorinterceptor) { this.interceptor=interceptor; } publicvoidIntercept(IInvocationinvocation) { this.interceptor.ToInterceptor().Intercept(invocation); } } publicclassLoggerAsyncInterceptor:IAsyncInterceptor { publicvoidInterceptAsynchronous(IInvocationinvocation) { //... } publicvoidInterceptAsynchronous(IInvocationinvocation) { //... } publicvoidInterceptSynchronous(IInvocationinvocation) { //... } } staticvoidMain(string[]args) { ContainerBuilderbuilder=newContainerBuilder(); //注册拦截器 builder.RegisterType ().AsSelf(); builder.RegisterType ().AsSelf(); //注册要拦截的服务 builder.RegisterType ().AsImplementedInterfaces() .EnableInterfaceInterceptors()//启用接口拦截 .InterceptedBy(typeof(LoggerInterceptor));//指定拦截器 varcontainer=builder.Build(); IProductRepositoryproductRepo=container.Resolve (); productRepo.Get(); }
以上就是C#使用Castle实现AOP及如何用Autofac集成Castle的详细内容,更多关于C#使用Castle实现AOP的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。