前言
最近越來越多的同學關注到AspectCore,並且提出不少中肯的建議,其中最多的提議是希望能夠看到更多的關於AspectCore使用方式的文章和Demo。那么在這篇文章里,我們就來聊聊AspectCore核心之一的動態代理。
動態代理
在.NET平台中,靜態織入和動態代理是實現AOP的兩種方式。其中靜態織入在編譯時通過在MSBiuld執行自定義的Build Task來攔截編譯過程,在生成的程序集里插入自己的IL。而動態代理則是在運行時通過Emit技術生成動態程序集和動態代理類型從而對目標方法進行攔截。不管那種方式,都需要對MSIL有足夠的理解,如果讀者想要學習MSIL相關的技術,我在這里推薦《NET探秘MSIL權威指南》一書。
AspectCore使用了動態代理作為AOP的實現,而不使用理論上性能更優的靜態織入實現,是由於個人覺得動態代理方式可以做到更好的IoC進行集成並且能夠在切面中獲取更多的運行時元數據信息,並且在經過不斷優化后,AspectCore動態代理的性能已經不落后靜態織入的實現方式。
如何使用
在之前的文章里,只是簡單的介紹了AspectCore,導致了很多同學不知道如何在項目里使用AspectCore(^~^,求輕拍~)。下面就來講一下如何在IoC環境和非IoC環境里使用AspectCore的AOP。
首先通過nuget獲取AspectCore:
Install-Package AspectCore.Core
AspectCore中動態代理api在AspectCore.DynamicProxy命名空間中,所以我們需要先引入命名空間
using AspectCore.DynamicProxy;
在非IoC環境中,只使用AOP的話,AspectCore提供了ProxyGeneratorBuilder作為代理生成器創建的入口
ProxyGeneratorBuilder proxyGeneratorBuilder = new ProxyGeneratorBuilder();
IProxyGenerator proxyGenerator = proxyGeneratorBuilder.Build();
IProxyGenerator提供了CreateClassProxy方法創建class代理和CreateInterfaceProxy方法創建interface代理,創建的代理類被定義在命名為AspectCore.DynamicProxy.Generator的動態程序集中,並且代理類使用AspectCore.DynamicGenerated命名空間。
我們先來定義一個簡單的攔截器,接着定義一個interface和它的簡單實現,並創建interface的代理:
class Program
{
static void Main(string[] args)
{
ProxyGeneratorBuilder proxyGeneratorBuilder = new ProxyGeneratorBuilder();
IProxyGenerator proxyGenerator = proxyGeneratorBuilder.Build();
SampleInterface sampleInterface = proxyGenerator.CreateInterfaceProxy<SampleInterface,SampleClass>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();
Console.ReadKey();
}
}
public class SampleInterceptor : AbstractInterceptorAttribute
{
public override Task Invoke(AspectContext context, AspectDelegate next)
{
Console.WriteLine("call interceptor");
return context.Invoke(next);
}
}
public class SampleClass : SampleInterface
{
public virtual void Foo() { }
}
[SampleInterceptor]
public interface SampleInterface
{
void Foo();
}
將會輸出:
AspectCore.DynamicGenerated.SampleInterface1
call interceptor
同時,IProxyGenerator提供了若干重載的擴展方法來創建已有類或接口實例的代理,可在ProxyGeneratorExtensions中找到並使用它們。
在IoC中使用AspectCore.DynamicProxy
AspectCore在設計之初就考慮AOP和IoC的集成使用,並提供AOP抽象接口以兼容不同IoC,目前已實現和AspectCore.DynamicProxy集成的IoC框架有:
- AspectCore.Injector(AspectCore Framework的內置IoC)
- Microsoft.Extensions.DependencyInjection(Asp.Net Core的內置DI框架)
- Autofac
下面我們分別看一下在三個IoC中如何使用AspectCore.DynamicProxy。
AspectCore.Injector
AspectCore.Injector中內置了對AspectCore.DynamicProxy的支持,所以我們可以直接使用它:
IServiceContainer serviceContainer = new ServiceContainer();
serviceContainer.AddType<SampleInterface, SampleClass>();
IServiceResolver serviceResolver = serviceContainer.Build();
SampleInterface sampleInterface = serviceResolver.Resolve<SampleInterface>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();
輸出:
AspectCore.DynamicGenerated.SampleClass
call interceptor
Microsoft.Extensions.DependencyInjection
AspectCore提供AspectCore.Extensions.DependencyInjection包集成Microsoft.Extensions.DependencyInjection和AspectCore.DynamicProxy。
通過nuget獲取:
Install-Package AspectCore.Extensions.DependencyInjection
AspectCore提供了針對IServiceCollection的擴展方法AddDynamicProxy注冊動態代理的接口和相關攔截器配置,並需要使用BuildAspectCoreServiceProvider創建被DynamicProxy接管的ServiceProvider:
IServiceCollection services = new ServiceCollection();
services.AddTransient<SampleInterface, SampleClass>();
services.AddDynamicProxy();
IServiceProvider serviceProvider = services.BuildAspectCoreServiceProvider();
SampleInterface sampleInterface = serviceProvider.GetService<SampleInterface>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();
輸出:
AspectCore.DynamicGenerated.SampleClass
call interceptor
Autofac
AspectCore提供AspectCore.Extensions.Autofac包集成Autofac和AspectCore.DynamicProxy。
通過nuget獲取:
Install-Package AspectCore.Extensions.Autofac
AspectCore提供了針對ContainerBuilder的擴展方法RegisterDynamicProxy注冊動態代理的接口和相關攔截器配置
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<SampleClass>().As<SampleInterface>();
builder.RegisterDynamicProxy();
var container = builder.Build();
SampleInterface sampleInterface = container.Resolve<SampleInterface>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();
輸出:
AspectCore.DynamicGenerated.SampleClass
call interceptor
有問題反饋
如果您有任何問題,請提交 Issue 給我們。
Github : https://github.com/dotnetcore/AspectCore-Framework
AspectCore QQ群: 306531723
