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. echarts图表x,y轴的设置

    https://www.cnblogs.com/cjh-strive/p/11065005.html xAxis属性代表echarts图表的x轴设置代码如下 xAxis : [ { type : 'c ...

  2. 1066 Root of AVL Tree (25分)(AVL树的实现)

    An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...

  3. 安装 elasticsearch For LINUX

    官网下载地址 https://www.elastic.co/cn/downloads/elasticsearch 选择版本为LINUX 当前版本为 es-7.6.2 用tar 命令解压 tar -zx ...

  4. VBScript - 弹出“文件选择对话框”方法大全!

    本文记录,VBScript 中,各种打开 "文件选择对话框" 的方法. 实现方法-1 (mshta.exe): 首先,我们要实现的就是,弹出上面的这个"文件选择对话框&q ...

  5. C++类的成员初始化

    C++类的成员初始化 学到一个类的成员初始化,目前已知的用途是给类内部的const类型变量进行赋值. 首先,如果像这么干,编译器会报错. class MyClass{ public: Myclass( ...

  6. 【php】正则表达式

    一.生活当中的正则表达式: a)Notepad++.word等这些具有编辑功能的软件,都具有一个查找.替换的功能,这个功能,其实就属于正则模式的一种匹配.替换:包括windows当中可以实现的查找,也 ...

  7. Thinkphp6源码分析之解析,Thinkphp6路由,Thinkphp6路由源码解析,Thinkphp6请求流程解析,Thinkphp6源码

    Thinkphp6源码解析之分析 路由篇-请求流程 0x00 前言: 第一次写这么长的博客,所以可能排版啊,分析啊,什么的可能会比较乱.但是我大致的流程已经觉得是说的够清楚了.几乎是每行源码上都有注释 ...

  8. C++ memset函数用法

    #include<stdio.h>#include<string.h>int main(){ char buffer[] = "I love you!"; ...

  9. JAVA中基本类型和包装类之间的相互转换

    转自:https://www.imooc.com/code/2250 仅做个人学习记录之用,侵删. 基本类型和包装类之间经常需要互相转换,以 Integer 为例(其他几个包装类的操作雷同哦): 在 ...

  10. android性能测试--CPU、内存