最近实现了一个 AOP 框架 – FluentAspects,API 基本稳定了,写篇文章分享一下这个 AOP 框架的设计。

整体设计

概览

IProxyTypeFactory

用来生成代理类型,默认提供了基于 Emit 动态代理的实现,基于接口设计,可以扩展为其他实现方式

接口定义如下:

public interface IProxyTypeFactory
{Type CreateProxyType(Type serviceType);Type CreateProxyType(Type serviceType, Type implementType);
}

IProxyFactory

用来生成代理实例,默认实现是基于 IProxyTypeFactory 生成代理类型之后创建实例

接口定义如下:

public interface IProxyFactory
{object CreateProxy(Type serviceType, object[] arguments);object CreateProxy(Type serviceType, Type implementType, params object[] arguments);object CreateProxyWithTarget(Type serviceType, object implement, object[] arguments);
}

IInvocation

执行上下文,默认实现就是方法执行的上下文,包含了代理方法信息、被代理的方法信息、方法参数,返回值以及用来自定义扩展的一个 Properties 属性

public interface IInvocation
{MethodInfo ProxyMethod { get; }object ProxyTarget { get; }MethodInfo Method { get; }object Target { get; }object[] Arguments { get; }Type[] GenericArguments { get; }object ReturnValue { get; set; }Dictionary<string, object> Properties { get; }
}

IInterceptor

拦截器,用来定义公用的处理逻辑,方法拦截处理方法

接口定义如下:

public interface IInterceptor
{Task Invoke(IInvocation invocation, Func<Task> next);
}

invocation 是方法执行的上下文,next 代表后续的逻辑处理,类似于 asp.net core 里的 next ,如果不想执行方面的方法不执行 next 逻辑即可

IInterceptorResolver

用来根据当前的执行上下文获取到要执行的拦截器,默认是基于 FluentAPI 的实现,但是如果你特别想用基于 Attribute 的也是可以的,默认提供了一个 AttributeInterceotorResovler,你也可以自定义一个适合自己的 InterceptorResolver

public interface IInterceptorResolver
{IReadOnlyList<IInterceptor> ResolveInterceptors(IInvocation invocation);
}

IInvocationEnricher

上面 IInvocation 的定义中有一个用于扩展的 Properties,这个 enricher 主要就是基于 Properties 来丰富执行上下文信息的,比如说记录 TraceId 等请求链路追踪数据,构建方法执行链路等

public interface IEnricher<in TContext>
{void Enrich(TContext context);
}
public interface IInvocationEnricher : IEnricher<IInvocation>
{
}

AspectDelegate

AspectDelegate 是用来将构建要执行的代理方法的方法体的,首先执行注册的 InvocationEnricher,丰富上下文信息,然后根据执行上下文获取要执行的拦截器,构建一个执行委托,生成委托使用了之前分享过的 PipelineBuilder 构建中间件模式的拦截器,执行拦截器逻辑

// apply enrichers
foreach (var enricher in FluentAspects.AspectOptions.Enrichers)
{try{enricher.Enrich(invocation);}catch (Exception ex){InvokeHelper.OnInvokeException?.Invoke(ex);}
}// get delegate
var builder = PipelineBuilder.CreateAsync(completeFunc);
foreach (var interceptor in interceptors)
{builder.Use(interceptor.Invoke);
}
return builder.Build();

更多信息可以参考源码: https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Aspect/AspectDelegate.cs

使用示例

推荐和依赖注入结合使用,主要分为以微软的注入框架为例,有两种使用方式,一种是手动注册代理服务,一种是自动批量注册代理服务,来看下面的实例就明白了

手动注册代理服务

使用方式一,手动注册代理服务:

为了方便使用,提供了一些 AddProxy 的扩展方法:

IServiceCollection services = new ServiceCollection();
services.AddFluentAspects(options =>{// 注册拦截器配置options.NoInterceptProperty<IFly>(f => f.Name);options.InterceptAll().With<LogInterceptor>();options.InterceptMethod<DbContext>(x => x.Name == nameof(DbContext.SaveChanges)|| x.Name == nameof(DbContext.SaveChangesAsync)).With<DbContextSaveInterceptor>();options.InterceptMethod<IFly>(f => f.Fly()).With<LogInterceptor>();options.InterceptType<IFly>().With<LogInterceptor>();// 注册 InvocationEnricheroptions.WithProperty("TraceId", "121212");});
// 使用 Castle 生成代理
services.AddFluentAspects(options =>{// 注册拦截器配置options.NoInterceptProperty<IFly>(f => f.Name);options.InterceptAll().With<LogInterceptor>();options.InterceptMethod<DbContext>(x => x.Name == nameof(DbContext.SaveChanges)|| x.Name == nameof(DbContext.SaveChangesAsync)).With<DbContextSaveInterceptor>();options.InterceptMethod<IFly>(f => f.Fly()).With<LogInterceptor>();options.InterceptType<IFly>().With<LogInterceptor>();// 注册 InvocationEnricheroptions.WithProperty("TraceId", "121212");}, builder => builder.UseCastle());services.AddTransientProxy<IFly, MonkeyKing>();
services.AddSingletonProxy<IEventBus, EventBus>();
services.AddDbContext<TestDbContext>(options =>
{options.UseInMemoryDatabase("Test");
});
services.AddScopedProxy<TestDbContext>();var serviceProvider = services.BuildServiceProvider();

批量自动注册代理服务

使用方式二,批量自动注册代理服务:

IServiceCollection services = new ServiceCollection();
services.AddTransient<IFly, MonkeyKing>();
services.AddSingleton<IEventBus, EventBus>();
services.AddDbContext<TestDbContext>(options =>
{options.UseInMemoryDatabase("Test");
});var serviceProvider = services.BuildFluentAspectsProvider(options =>{options.InterceptAll().With<TestOutputInterceptor>(output);});// 使用 Castle 来生成代理
var serviceProvider = services.BuildFluentAspectsProvider(options =>{options.InterceptAll().With<TestOutputInterceptor>(output);}, builder => builder.UseCastle());// 忽略命名空间为 Microsoft/System 的服务类型
var serviceProvider = services.BuildFluentAspectsProvider(options =>{options.InterceptAll().With<TestOutputInterceptor>(output);}, builder => builder.UseCastle(), t=> t.Namespace != null && (t.Namespace.StartWith("Microsft") ||t.Namespace.StartWith("Microsft")));

More

上面的两种方式个人比较推荐使用第一种方式,需要拦截什么就注册什么代理服务,自动注册可能会生成很多不必要的代理服务,个人还是比较喜欢按需注册的方式。

这个框架还不是很完善,有一些地方还是需要优化的,目前还是在我自己的类库中,因为我的类库里要支持 net45,所以有一些不好的设计改起来不太方便,打算迁移出来作为一个单独的组件,直接基于 netstandard2.0/netstandard2.1, 甩掉 netfx 的包袱。

最后:

需要领取全部面试题文档的小伙伴看这里!
更多分享:前端字节跳动真题解析

库中,因为我的类库里要支持 net45,所以有一些不好的设计改起来不太方便,打算迁移出来作为一个单独的组件,直接基于 netstandard2.0/netstandard2.1, 甩掉 netfx 的包袱。

最后:

需要领取全部面试题文档的小伙伴看这里!
更多分享:前端字节跳动真题解析

  • [外链图片转存中…(img-sNpztshp-1627022865134)]

web开发视频教程,CSS颜色基本样式相关推荐

  1. 6天移动web开发视频教程_针对Web和移动开发人员的完整视频解决方案

    6天移动web开发视频教程 This article was originally published on Cloudinary Blog. Thank you for supporting the ...

  2. IntelliJ IDEA 8.1.3 Web开发视频教程

    IntelliJ IDEA 8.1.3 Web开发视频教程

  3. 重拾web开发-DIV+CSS基础(总结)

    以下内容摘自网上各处本人只是总结并非完全原创,特此申明. 文档类型 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/ ...

  4. Web开发基础——CSS

    学习目标: •                CSS和HTML整合     •                CSS选择器的使用 学习内容: •                css和html整合   ...

  5. java css路径_java web开发中CSS路径有问题吗,运行jsp文件为什么找不到css文件?...

    ---------------------------------------------------------------------------------------------------- ...

  6. Web前端——用CSS的常用样式制作一个炫酷的按钮

    文章目录 笔记:CSS的常用样式 炫酷按钮效果实现 笔记:CSS的常用样式 边框以及弧度样式 border-width:边框的线条宽度. border-style:边框的样式,例如 solid实现 d ...

  7. web开发培训,CSS颜色基本样式

    2.极简版promise 2.1 基础特性 new Promise((resolve,reject)=>{ //excutorsetTiemout(()=>{resolve(1) //re ...

  8. CSS的浮动属性,CSS颜色基本样式

    前言 校招 -1 年 这个阶段还属于成长期,更需要看重的是你的基础和热情.对于 JS 基础,计算机基础,网络通信,算法等部分的要求会相对高一些.毕竟这个阶段比较难考察你的业务项目中的沉淀,所以只能从基 ...

  9. vim 下web开发html css js插件

    Vim下的Web开发之html,CSS,javascript插件 HTML 下载HTML.zip 解压HTML.zip,然后将里面的所有文件copy到C:\Program Files\Vim\vimf ...

  10. web开发 DIV+CSS规范命名集合

    我们开发CSS+DIV网页(Xhtml)时候,比较困惑和纠结的事就是CSS命名,特别是新手不知道什么地方该如何命名,怎样命名才是好的方法. 命名规则说明: 1).所有的命名最好都小写 2).属性的值一 ...

最新文章

  1. CPU的自动调度矩阵乘法
  2. php 自定义文件后缀,自定义更改服务器asp/php/.net等文件后缀名
  3. 微博 用户画像_微博/抖音/快手/小红书/B站内容营销和粉丝画像研究
  4. 手机来电秀怎么开启_360手机卫士怎么设置来电秀 360手机卫士来电秀设置方法...
  5. 10停止nginx命令 win_Linux下配置Nginx并使用https协议
  6. Spring核心系列之ApplicationContext
  7. SpringBoot2.1.15(26) WebFlux快速上手——响应式Spring的道法术器
  8. 【前端 · 面试 】HTTP 总结(四)—— HTTP 状态码
  9. 渗透测试/应急演练过程中metasploit制作木马连接失败问题排查
  10. 软件测试02_软件生命周期软件测试流程
  11. 细数魔兽争霸作弊工具排行
  12. 王者服务器维护8月四日,王者荣耀体验服弈星重做上线 8月4日停机更新
  13. 修改andriod模拟器的IMEI,IMSI,手机号,SIM卡号
  14. openmediavault安装
  15. 第三章 part2 单调性与极值
  16. php.ini配置文件详解(mac nginx1.8.0 php5.6 )持续更新中
  17. 贴吧涂鸦–毕加索的画板
  18. 数字华容道算法生有解
  19. 如何成为一个合格的产品经理
  20. python编写同步欧氏距离轨迹压缩_基于相对同步欧氏距离筛选的在线GPS轨迹数据压缩算法.PDF...

热门文章

  1. 实用技巧 teamviewer高清显示
  2. python金融衍生品_Python 金融数据分析:单一风险衍生品估值丨数析学院
  3. python实现归结演绎推理_人工智能——归结演绎推理
  4. 复变函数——一到三章总结
  5. CVPR2019目标检测论文汇总
  6. 网页设计1-1李清照人物简介
  7. 高德AR驾车导航解决方案
  8. Unity 自定义standard shader
  9. php命名空间的设计思想和缺点
  10. 推荐系统实战(四)——利用社交网络数据