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 ...
随机推荐
- 记录一次读取hdfs文件时出现的问题java.net.ConnectException: Connection refused
公司的hadoop集群是之前的同事搭建的,我(小白一个)在spark shell中读取hdfs上的文件时,执行以下指令 >>> word=sc.textFile("hdfs ...
- 了解LockSupport工具类
介绍: 在网上也没有找到太多的东西,大概说了一下,这个工具类的所有方法都是静态的,底层采用UNSAFE直接操作的内存,可以实现线程的阻塞和唤醒 可以看到他的park方法调用的是UNSAFE的park方 ...
- java版飞机大战代码
@ 目录 前言 Plane PlaneStatus类 Power类 Gift Diji play类 over类 MainFrame主类 MyZiDan DijiZiDan Before 前言 很久之前 ...
- Windows常用的网络命令
命令 说明 ipconfig 查看网络配置的信息 ping 测试网络是否连通 tracert 网络诊断工具,可以列出分组经过的路由节点 net 有添加用户.开启服务等功能 netstat 显示协议统计 ...
- java基本权限指南之:文件和共享目录的基本权限
简介 java程序是跨平台的,可以运行在windows也可以运行在linux.但是平台不同,平台中的文件权限也是不同的.windows大家经常使用,并且是可视化的权限管理,这里就不多讲了. 本文主要讲 ...
- Android 滑动删除控件推荐
implementation 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.3.0' <?xml version="1.0" enc ...
- python-Requests模块的使用
1. Requests简介 Requests模块是一个用于网络访问的模块,其实类似的模块有很多,比如urllib,urllib2,httplib,httplib2,他们基本都提供相似的功能,那为什么R ...
- 面试阿里,首先要掌握的 Java 泛型,帮你一次性搞懂!
引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除. 泛型基础 泛型类 我们首 ...
- css3系列之属性选择器
Attribute Selectors(属性选择器) E[attr ~="val"] E[attr |="val"] E[attr ^="val&qu ...
- js实现长按显示全部内容
js实现文字超出省略号显示时长按显示全部 元素内容超出省略号显示时长按该元素,生成toast弹窗(id:toolkitContainer),以显示全部内容 #toolkitContainer { ma ...