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);
}
privateasyncTaskInternalInterceptAsynchronous(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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。