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. JS数据结构与算法 - 二叉树(一)基本算法

    仅供JavaScript刷题参考用. 二叉查找树和平衡二叉树 其它树:满二叉树.完全二叉树.完美二叉树.哈弗曼树.二叉查找树BST.平衡二叉树AVL 了解:红黑树,是一种特殊的二叉树.这种树可以进行高 ...

  2. JVM 理解性学习(一)

    重新学习,重新理解 1.类加载过程等 验证:.class 文件加载到 JVM 里的时候,会验证下该文件是否符合 JVM 规范. 准备:给实体类分配内存空间,以及给类变量(static 修饰)分配&qu ...

  3. 查找 mysql 配置文件 my.cnf

    $ locate my.cnf 看看你的linux上有多少个my.cnf,一般都配置为/etc/my.cnf

  4. 中阶d03.2 JDBC联合properties使用,通过读取本地配置文件为代码传递参数

    * 使用properties读取本地配置文件为代码传递参数 * url.用户名.密码.驱动地址等配置可以在配置文件中使用 main package zj_1_JDBC.properties; impo ...

  5. 【高并发】不废话,言简意赅介绍BlockingQueue

    写在前面 最近,有不少网友留言提问:在Java的并发编程中,有个BlockingQueue,它是个阻塞队列,为何要在并发编程里使用BlockingQueue呢?好吧,今天,就临时说一下Blocking ...

  6. 使用Network Emulator Toolkit工具模拟网络丢包测试(上)

    弱网络测试包括延时和丢包二种场景下应用的功能是否正常: 网络延时测试使用Fiddler工具控制上下行数据传输延时时间来模拟网络延时场景: 网络丢包测试使用Network Emulator Toolki ...

  7. 利用 Github 网络钩子实现自动化部署

    GitHub 的网络钩子(webhook)功能,可以很方便的实现自动化部署.本文记录了使用 Node.js 的开发部署过程,当项目的 master 分支被推时,将在服务器进行自动部署 添加网路钩子 在 ...

  8. asp.net mvc 接收jquery ajax发送的数组对象

    <script type="text/javascript"> $(function () { var obj = { name: "军需品", m ...

  9. Leetcode802-找到最终的安全状态(Python3)

    刚开始没思路,还以为是利用二维矩阵直接标记节点间的有向路径,最后循环遍历就能得到结果,结果最后发现方向是错的,之后看了大佬们写的代码,发现原来是用出度来实现节点是否安全的. 照着大佬们的思路重新写了一 ...

  10. Mybatis源码详解系列(三)--从Mapper接口开始看Mybatis的执行逻辑

    简介 Mybatis 是一个持久层框架,它对 JDBC 进行了高级封装,使我们的代码中不会出现任何的 JDBC 代码,另外,它还通过 xml 或注解的方式将 sql 从 DAO/Repository ...