Norns.Urd 中的一些设计
Norns.Urd 是什么?
Norns.Urd 是一个基于emit实现动态代理的轻量级AOP框架.
版本基于 netstandard2.0. 所以哪些.net 版本能用你懂的。
完成这个框架的目的主要出自于个人以下意愿:
- 静态AOP和动态AOP都实现一次
- 如果不实现DI,怎么将AOP框架实现与其他现有DI框架集成
- 一个AOP 如何将 sync 和 async 方法同时兼容且如何将实现选择权完全交予用户
希望该库能对大家有些小小的作用
中文文档在:https://fs7744.github.io/Norns.Urd/zh-cn/index.html
顺便求个star, github 地址:https://github.com/fs7744/Norns.Urd
对了,如果不了解AOP的同学,可以看看这些文章:
面向切面的程序设计
什么是面向切面编程AOP?
AOP 有几种实现方式?
Norns.Urd 中的一些设计
Norns.Urd的实现前提
由于Norns.Urd的实现基于以下两点前提
将 sync 和 async 方法同时兼容且如何将实现选择权完全交予用户
- 其实这点还好,工作量变成两倍多一些就好,sync 和 async 完全拆分成两套实现。
- 提供给用户的Interceptor接口要提供 sync 和 async 混合在一套实现代码的方案,毕竟不能强迫用户实现两套代码,很多场景用户不需要为sync 和 async 的差异而实现两套代码
不包含任何内置DI,但要整体都为支持DI而作
- 其实如果内置DI容器可以让支持 generic 场景变得非常简单,毕竟从DI容器中实例化对象时必须有明确的类型,但是呢,现在已经有了那么多实现的库了,我就不想为了一些场景而实现很多功能(我真的懒,否则这个库也不会写那么久了)
- 但是DI容器确实解耦非常棒,我自己都常常因此受益而减少了很多代码修改量,所以做一个aop库必须要考虑基于DI容器做支持,这样的话,di 支持的 open generic / 自定义实例化方法都要做支持,并且aop里面还得提供用户调用DI的方法,否则还不好用了 (这样算下来,我真的偷懒了吗?我是不是在给自己挖坑呀?)
如何设计解决的?
目前方案不一定完美,暂时算解决了问题而已 (有更好方案请一定要告诉我,我迫切需要学习)
提供什么样的拦截器编写模式给用户?
以前接触一些其他aop实现框架,很多都需要将拦截代码分为 方法前 / 方法后 / 有异常等等,个人觉得这样的形式还是一定程度上影响拦截器实现的代码思路,总觉得不够顺滑
但是像 ASP.NET Core Middleware就感觉非常不错,如下图和代码:

app.Run(async context =>
{
await context.Response.WriteAsync("Hello, World!");
});
拦截器也应该可以像这样做,所以拦截器的代码应该可以像这样:
public class ConsoleInterceptor
{
public async Task InvokeAsync(Context context, Delegate next)
{
Console.WriteLine("Hello, World!");
await next(context);
}
}
sync 和 async 方法如何拆分?又如何能合并在一起呢?用户有怎么自己选择实现sync 还是 async 或者两个都都实现呢?
public delegate Task AsyncAspectDelegate(AspectContext context);
public delegate void AspectDelegate(AspectContext context);
// 拆分:
// 由AspectDelegate 和 AsyncAspectDelegate 建立两套完全区分 sync 和 async 的Middleware调用链,具体使用哪个由具体被拦截的方法本身决定
public abstract class AbstractInterceptor : IInterceptor
{
public virtual void Invoke(AspectContext context, AspectDelegate next)
{
InvokeAsync(context, c =>
{
next(c);
return Task.CompletedTask;
}).ConfigureAwait(false)
.GetAwaiter()
.GetResult();
}
// 合并:
// 默认实现转换方法内容,这样各种拦截器都可以混在一个Middleware调用链中
public abstract Task InvokeAsync(AspectContext context, AsyncAspectDelegate next);
// 用户自主性选择:
// 同时提供sync 和 async 拦截器方法可以重载,用户就可以自己选择了
// 所以用户在 async 中可以调用专门的未异步优化代码了,也不用说在 sync 中必须 awit 会影响性能了,
// 你认为影响性能,你在乎就自己都重载,不在乎那就自己选
}
没有内置DI,如何兼容其他DI框架呢?
DI框架都有注册类型,我们可以通过 emit 生成代理类,替换原本的注册,就可以做到兼容。
当然每种DI框架都需要定制化的实现一些代码才能支持(唉,又是工作量呀)
AddTransient<IMTest>(x => new NMTest()), 类似这样的实例化方法怎么支持呢?
由于这种DI框架的用法,无法通过Func函数拿到实际会使用的类型,只能根据IMTest定义通过emit 生成 桥接代理类型,其伪码类似如下:
interface IMTest
{
int Get(int i);
}
class IMTestProxy : IMTest
{
IMTest instance = (x => new NMTest())();
int Get(int i) => instance.Get(i);
}
.AddTransient(typeof(IGenericTest<,>), typeof(GenericTest<,>)) 类似这样的 Open generic 怎么支持呢?
其实对于泛型,我们通过 emit 生成泛型类型一点问题都没有,唯一的难点是不好生成 Get<T>() 这样的方法调用, 因为IL需要反射找到的具体方法,比如Get<int>() Get<bool>() 等等,不能是不明确的 Get<T>()。
要解决这个问题就只能将实际的调用延迟到运行时调用再生成具体的调用,伪码大致如下:
interface GenericTest<T,R>
{
T Get<T>(T i) => i;
}
class GenericTestProxy<T,R> : GenericTest<T,R>
{
T Get<T>(T i) => this.GetType().GetMethod("Get<T>").Invoke(i);
}
Norns.Urd 中的一些设计的更多相关文章
- 介绍一个新库: Norns.Urd.HttpClient
Norns.Urd.HttpClient Norns.Urd.HttpClient 基于AOP框架 Norns.Urd实现, 是对 System.Net.Http下的 HttpClient封装,让大家 ...
- 看懂此文,不再困惑于 JS 中的事件设计
看懂此文,不再困惑于 JS 中的事件设计 今天刚在关注的微信公众号看到的文章,关于JS事件的,写的很详细也很容易理解,相关的知识点都有总结到,看完就有种很舒畅的感觉,该串起来的知识点都串起来了.反正一 ...
- JS 中的事件设计
看懂此文,不再困惑于 JS 中的事件设计 原文出处: aitangyong 抽空学习了下javascript和jquery的事件设计,收获颇大,总结此贴,和大家分享. (一)事件绑定的几种方式 ...
- 推荐一款基于Angular实现的企业级中后台前端/设计解决方案脚手架
ng-alain 是一个企业级中后台前端/设计解决方案脚手架,我们秉承 Ant Design 的设计价值观,目标也非常简单,希望在Angular上面开发企业后台更简单.更快速.随着『设计者』的不断反馈 ...
- Ceph中Bufferlist的设计与使用
转自:https://www.ustack.com/blog/bufferlist/ 如果非要在整个Ceph中,找出一个类最重要,我觉得非Bufferlist莫属了,原因很简单,因为Bufferlis ...
- mysql中数据库的设计
软件开发流程(CMMI): 1):项目启动; 2):项目计划: 3):需求分析; 需要得到的结果是什么? 4):系统设计; 该怎么做? 5):系统开发; 6):系统测试; 7):系 ...
- 在Eclipse中使用WindowBuilder设计Swing程序
在Eclipse中使用WindowBuilder设计Swing程序 Swing程序表示Java的客户端窗体程序,除了通过手动编写代码的方式设计Swing程序之外,Eclipse中还提供了一种W ...
- Java实现图形界面的三部曲及IDE中的窗口设计
设计和实现图形用户界面的工作主要有以下几点: • (1)创建组件(Component) • 创建组成界面的各种元素,如按钮.文本框等.• (2)指定布局(Layout) • 根据具体需要排列它们的位置 ...
- java中HashMap的设计精妙在哪?
摘要:本文结合图解和问题,教你一次性搞定HashMap 本文分享自华为云社区<java中HashMap的设计精妙在哪?用图解和几个问题教你一次性搞定HashMap>,作者:breakDaw ...
随机推荐
- ostringstream、istringstream、stringstream(转)
看一下C++风格的串流控制,C++引入了ostringstream.istringstream.stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件. istring ...
- git , repo out off memory
解决方法,建立swap # dd if=/dev/zero of=/root/myswapfile bs=1M count=1024 1024+0 records in 1024+0 records ...
- UNP——第四章,TCP套接字编程
1.socket 函数 首先被调用的函数,用于选择通信协议. socket调用成功后,得到的套接字为主动套接字CLOSED状态. PF 和 AF 的关系 PF的是协议族,AF是地址族,理论上一个PF包 ...
- CDC(跨时钟域)和亚稳态
- 关于backfill参数建议
前言 在做一个比较满的集群的扩容的时候,遇到了一些问题,在这里做下总结,一般来说很难遇到,扩容要趁早,不然出的问题都是稀奇古怪的一些问题 建议 环境一般来说在70%左右就需要考虑扩容了,这个时候的扩容 ...
- EOF和scanf函数
EOF和scanf函数 scanf函数的返回值 scanf函数返回成功读入的数据项数,读入数据时遇到了"文件结束(end of file)"或者错误则返回EOF,EOF定义为int ...
- kali 系列学习01 - 安装、vmtools、ssh服务和共享文件夹
Kali介绍Kali Linux是基于Debian的Linux发行版, 设计用于数字取证操作系统.面向专业的渗透测试和安全审计,超过300个渗透测试工具一.安装 1.在虚拟机中安装,详见 https: ...
- 历时两年零三个月,从刚毕业的外包到现在的阿里P7offer,我只做了这几件事
前言 最近,金九银十在即,很多人都在准备面试,特别给大家总结了 Java 程序员面试必备题,这份面试清单是我从 去年开始收集的,一方面是给公司招聘用,另一方面是想用它来挖掘我在 Java 技术栈中的技 ...
- Javascript 严格模式的一些理解
平常我们在ECMAscript5中可以声明以下的变量 num = 5; console.log(num);//输出的是变量5 而为了Javascript更合理.更安全.更严谨的方向发展,添加了一种新的 ...
- JavaScript中的链式调用
链模式 链模式是一种链式调用的方式,准确来说不属于通常定义的设计模式范畴,但链式调用是一种非常有用的代码构建技巧. 描述 链式调用在JavaScript语言中很常见,如jQuery.Promise等, ...