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
Reference
- https://github.com/WeihanLi/WeihanLi.Common/tree/dev/src/WeihanLi.Common/Aspect
- https://github.com/WeihanLi/SamplesInPractice/blob/master/FluentAspectSample/Program.cs
- https://github.com/dotnetcore/AspectCore-Framework
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/36109.html
標籤:.NET Core
上一篇:Quickuse.Caching 快速應用.快取組件
下一篇:打造更好用的 EF 自動審計
