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

FluentAspects -- 基于 Fluent API 的 Aop相关推荐

  1. Fluent API — 流畅API(基于Java介绍)

    Fluent API ,流畅API, 也称作流式API. Fluent API 是一种面向对象的API,主要基于方法链. 这个概念由Eric Evans​和​Martin Fowler​于 2005 ...

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

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

  3. FreeSql (四)实体特性 Fluent Api

    FreeSql 提供使用 Fluent Api, 在外部配置实体的数据库特性,Fluent Api 的方法命名与特性名保持一致,如下: fsql.CodeFirst.ConfigEntity<T ...

  4. thinkcmf5调用指定分类的二级_Tengine快速上手系列教程amp;视频:基于Python API的图片分类应用入门丨附彩蛋...

    前言:近期,Tengine团队加班加点,好消息接踵而来,OpenCV 4.3.0发布,OPEN AI LAB AIoT智能开发平台Tengine与OpenCV合作共同加速边缘智能,Tengine再获业 ...

  5. 你也可以玩转Skype -- 基于Skype API开发外壳程序入门

    原文:你也可以玩转Skype -- 基于Skype API开发外壳程序入门 Skype是目前这个星球上最厉害的IM+VOIP软件,Skype现在已经改变了全球2.8亿人的生活方式.你,值得拥有! :) ...

  6. Spring3基于注释驱动的AOP

    51CTO正在组织十佳博客评选请 Spring3基于注释驱动的AOP 实在是郁闷刚刚编辑了一篇文章,由于字数的原因,没发布成功,好我就分开写吧,今天向大家介绍的是Spring基于注释驱动的AOP,其实 ...

  7. 基于Winsock API的VC网络编程实战

    基于Winsock API的VC网络编程实战 随着计算机信息技术的飞速发展,互联网与人类社会的工作.生活越来越紧密相关,它已经成为人类获取.交流信息的重要途径和手段.所以当前对于开发人员来说,网络编程 ...

  8. EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射

    为什么80%的码农都做不了架构师?>>>    EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射 I.EF里的默认映射 上篇文章演示 ...

  9. 基于ArcGIS API for JavaScript加载天地图

    文章目录 前言 效果图 详细代码 总结 参考链接 前言 该篇主要介绍如何用ArcGIS JS API加载天地图,具体应用场景以及需求分析等,在上篇基于ArcGIS API for JavaScript ...

最新文章

  1. 多视图立体匹配论文分享:BlendedMVS
  2. 南云等PNAS研究论文:揭示儿童音乐学习向语言领域迁移的脑机制
  3. HBase基本概念和hbase shell常用命令用法
  4. AI:神经网络调参(数据、层数、batch大小,学习率+激活函数+正则化+分类/回归)并进行结果可视化
  5. 利用CSS设置页面的垂直居中效果
  6. 机器学习_机器不学习:从Spark MLlib到美图机器学习框架实践
  7. k8s边缘节点_边缘计算,如何啃下集群管理这块硬骨头?
  8. 【转】对路径**的访问被拒绝
  9. pytorch 中nn.MaxPool1d() 和nn.MaxPool2d()对比;nn.functional.max_pool1d
  10. Java学习不走弯路教程(16 用Ajava异步请求)
  11. chrome 开启HEVC硬件解码
  12. 如何利用excel中的数据源制作数据地图
  13. javascript之键盘事件
  14. 微信小程序:map组件的简单使用,标注callout与label简单用法
  15. Oracle 12C 基础知识与使用入门(修订版)
  16. 手机删掉的照片怎么恢复
  17. 【洛谷 P7299】 【并查集】 Dance Mooves S
  18. idea设置类注释和方法注释模板
  19. 【STM32F407开发板用户手册】第7章 STM32F407下载和调试方法(IAR8)
  20. 教师资格证报名显示内核服务器错误,中小学教师资格证报考支付卡状态失效是怎么回事?..._教师资格考试_帮考网...

热门文章

  1. 2.2 PostgreSQL 概念
  2. python 生成排列、组合以及选择
  3. C# 使用int.TryParse,Convert.ToInt32,(int)将浮点类型转换整数时的区别
  4. 在php中使用sockets:从新闻组中获取文章
  5. jQuery Pagination Ajax分页插件中文详解
  6. 共享没有权限访问权限_如何与家人共享SmartThings访问权限
  7. 【Redis源码分析】Redis命令处理生命周期
  8. 大数据在金融领域的应用及问题时
  9. 同一个PC只能运行一个应用实例(考虑多个用户会话情况)
  10. linux下ip命令用法