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

FluentAspects -- 基于 Fluent API 的 Aop的更多相关文章

  1. 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx EF 6 Code-Firs ...

  2. 实现一个简单的基于动态代理的 AOP

    实现一个简单的基于动态代理的 AOP Intro 上次看基于动态代理的 AOP 框架实现,立了一个 Flag, 自己写一个简单的 AOP 实现示例,今天过来填坑了 目前的实现是基于 Emit 来做的, ...

  3. 1.【使用EF Code-First方式和Fluent API来探讨EF中的关系】

    原文链接:http://www.c-sharpcorner.com/UploadFile/3d39b4/relationship-in-entity-framework-using-code-firs ...

  4. 基于注解的Spring AOP的配置和使用

    摘要: 基于注解的Spring AOP的配置和使用 AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.可以通过预编译方式和运行期动态代理实现在不 ...

  5. 使用 Fluent API 配置/映射属性和类型(摘自微软Data Access and Storage)

    使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...

  6. Entity Framework 实体框架的形成之旅--Code First模式中使用 Fluent API 配置(6)

    在前面的随笔<Entity Framework 实体框架的形成之旅--Code First的框架设计(5)>里介绍了基于Code First模式的实体框架的经验,这种方式自动处理出来的模式 ...

  7. Entity Framework Code First (五)Fluent API - 配置关系

    上一篇文章我们讲解了如何用 Fluent API 来配置/映射属性和类型,本文将把重点放在其是如何配置关系的. 文中所使用代码如下 public class Student { public int ...

  8. 使用Fluent API 配置/映射属性和类型

    Code First约定-Fluent API配置 使用Fluent API 配置/映射属性和类型 简介 通常通过重写派生DbContext 上的OnModelCreating 方法来访问Code F ...

  9. 使用 Fluent API 配置/映射属性和类型

    使用 Fluent API 配置/映射属性和类型 使用实体框架 Code First 时,默认行为是使用一组 EF 中内嵌的约定将 POCO 类映射到表.但是,有时您无法或不想遵守这些约定,需要将实体 ...

随机推荐

  1. Vue设置路由跳转的两种方法: <router-link :to="..."> 和router.push(...)

    一.<router-link :to="..."> to里的值可以是一个字符串路径,或者一个描述地址的对象.例如: // 字符串 <router-link to= ...

  2. Appium自动化(1) - 环境准备详细教程

    Appium需要用到的工具 链接:https://pan.baidu.com/s/1od9x-1l0ALGRT5T6QFDHWg 提取码:bnhq 安装Appium Pyhton client包 1. ...

  3. HDU1074:Doing Homework(状压DP)

    Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  4. 分治与递归-Fibonacci数列兔子问题

    裴波那契(Fibonacci leonardo,约1170-1250)是意大利著名数学家.在他的著作<算盘书>中许多有趣的问题,最富成功的问题是著名的“兔子繁殖问题”: 如果每对兔子每月繁 ...

  5. django_rest_framework视图传递参数给序列化器

    django_rest_framework视图传递参数给序列化器 视图中默认可以将request.data传递给序列化器,但request.data是不可更改的对象,但又想将额外的参数传递给序列化器 ...

  6. MTK Android 计算器Calculator输入暗码!77!+,启动工厂测试apk

    Android8.0 计算器Calculator输入暗码!77!+,启动工厂测试apk 路径: packages/apps/ExactCalculator/src/com/android/calcul ...

  7. JAVA中使用Date和SimpleDateFromat类表示时间

    转自:https://www.imooc.com/code/2335 仅做个人学习保存之用,侵删! 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Dat ...

  8. 学习《深入应用c++11》1

    C++11 让程序更简洁.更优雅 可调用对象 是一个函数指针 是一个具有operator()成员函数的类对象(仿函数) 是一个可被装换为函数指针的类对象 是一个类的成员(函数)指针 void func ...

  9. AJ学IOS(32)UI之Quartz2D矩阵操作和图片剪切

    AJ分享,必须精品 矩阵操作 矩阵操作:(旋转,缩放,平移) 通过矩阵操作,把画出来的东西进行形变 旋转操作 方法:CGContextRotateCTM(<#CGContextRef c#> ...

  10. ASE project demo:pdf

    欢迎使用 pdf ~ 主页面如下,整个app风格一致,保持简约舒适的视觉体验~ 侧边栏打开,可选择打开新的pdf文件,返回主页面,打开本地生词本,登录等操作~ 可以点击侧边栏OpenFile打开新的p ...