FluentAspects -- 基於 Fluent API 的 Aop
Intro
上次我們做了一個簡單的 AOP 實現示例,但是實現起來主要是基於 Attribute
來做的,對於程式碼的侵入性太強,於是嘗試實現基於 Fluent API 的方式來做 AOP 。
抽象 InterceptorResolver
原來獲取方法執行的 Interceptor 是通過 Attribute
來獲取的,現在我們只需要將獲取 Interceptor 的邏輯抽象出來就可以實現不必依賴於 Attribute
了
方法執行上下文定義:
public interface IInvocation
{
public MethodInfo ProxyMethod { get; }
public object ProxyTarget { get; }
public MethodInfo Method { get; }
public object Target { get; }
public object[] Arguments { get; }
Type[] GenericArguments { get; }
public object ReturnValue { get; set; }
}
方法攔截器 Interceptor
介面定義:
public interface IInterceptor
{
Task Invoke(IInvocation invocation, Func<Task> next);
}
自定義 Interceptor 只需要繼承這個介面實現相應的邏輯就好了
獲取 IInterceptorResolver
介面定義:
public interface IInterceptorResolver
{
IReadOnlyCollection<IInterceptor> ResolveInterceptors(IInvocation invocation);
}
原來基於 Attribute
獲取 Interceptor 的方式可以實現一個 AttributeInterceptorResolver
想要基於 Fluent API 來獲取 Interceptor ,只需要實現基於 Fluent API 的 InterceptorResolver
就可以了,具體的實現可以參考 FluentConfigInterceptorResolver
示例預覽
測試服務定義:
public interface ISvc1
{
void Invoke();
}
public interface ISvc2
{
void Invoke();
}
public class Svc2 : ISvc2
{
public void Invoke()
{
Console.WriteLine($"invoking in {GetType().Name} ...");
}
public void Invoke2()
{
Console.WriteLine($"invoking in {GetType().Name} ...");
}
}
public class Svc3
{
public virtual void Invoke()
{
Console.WriteLine($"invoking in {GetType().Name} ...");
}
}
public class Svc4
{
public virtual void Invoke()
{
Console.WriteLine($"invoking in {GetType().Name} ...");
}
public void Invoke2()
{
Console.WriteLine($"invoking2 in {GetType().Name} ...");
}
public virtual void Invoke3()
{
Console.WriteLine($"invoking3 in {GetType().Name} ...");
}
}
測試 Interceptor
internal class LogInterceptor : IInterceptor
{
public async Task Invoke(IInvocation invocation, Func<Task> next)
{
Console.WriteLine($"invoke {invocation.ProxyMethod} in {GetType().Name} begin");
await next();
Console.WriteLine($"invoke {invocation.ProxyMethod} in {GetType().Name} end");
}
}
測試程式碼:
public static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddFluentAspects(options =>
{
// 為所有攔截的方法新增攔截器
options.InterceptAll()
.With<LogInterceptor>()
;
// 對 Svc3 型別禁用攔截器
options.NoInterceptType<Svc3>();
// Svc4 型別的 Invoke3() 方法禁用攔截器
options.NoInterceptMethod<Svc4>(s => s.Invoke3());
});
services.AddTransientProxy<Svc4>();
var serviceProvider = services.BuildServiceProvider();
var proxyFactory = serviceProvider.GetRequiredService<IProxyFactory>();
var svc1 = proxyFactory.CreateProxy<ISvc1>();
svc1.Invoke();
Console.WriteLine();
var svc2 = proxyFactory.CreateProxy<ISvc2, Svc2>();
svc2.Invoke();
Console.WriteLine();
var svc3 = proxyFactory.CreateProxy<Svc3>();
svc3.Invoke();
Console.WriteLine();
var svc4 = proxyFactory.CreateProxyWithTarget<ISvc2, Svc2>(new Svc2());
svc4.Invoke();
Console.WriteLine();
// 直接從註冊的服務中獲取
var svc5 = serviceProvider.GetRequiredService<Svc4>();
svc5.Invoke();
Console.WriteLine();
svc5.Invoke2();
Console.WriteLine();
svc5.Invoke3();
Console.WriteLine();
Console.WriteLine("finished");
Console.ReadLine();
}
輸出結果預覽:
More
最近十幾天的時間一直在搞這個,相比之前寫的示例,真正實現一個完整的 AOP 框架還是要做比較多的事情的,之前的 AOP 示例,沒有考慮泛型,也沒有什麼設計,所以前面的示例只能算是一個小玩具。
在實現的過程中,參考了很多 AspectCore 的程式碼,有一些程式碼甚至是直接從 AspectCore 裡抄過來的。
推薦大家有機會研究學習一下檸檬大佬的 AspectCore 的原始碼,這個 AOP 框架的程式碼組織,程式碼細節都挺不錯的。
AspectCore 原始碼地址: https://github.com/dotnetcore/AspectCore-Framework