.NET 云原生架构师训练营(责任链模式)--学习笔记
目录
- 责任链模式
- 源码
责任链模式

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
何时使用:在处理消息的时候以过滤很多道
使用场景:
- 有多个对象可以处理同一个请求,具体到哪个对象处理该请求由运行时刻自动确定
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
- 可动态指定一组对象处理请求

源码
https://github.com/dotnet/aspnetcore/
在 ASP .NET Core 源码的 Kestrel 当中,构建 KestrelConnection 之后传送给 HttpConnectionMiddleware 中间件处理管道
在目录 Microsoft.AspNetCore.Server.Kestrel.Core 下面的 KestrelServerImpl 中有一个 UseHttpServer 方法
options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);
在 UseHttpServer 方法中构造了一个 HttpConnectionMiddleware,构造之后调用了 IConnectionBuilder 的 Use 方法
public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols, bool addAltSvcHeader) where TContext : notnull
{
var middleware = new HttpConnectionMiddleware<TContext>(serviceContext, application, protocols, addAltSvcHeader);
return builder.Use(next =>
{
return middleware.OnConnectionAsync;
});
}
在 IConnectionBuilder 的实现类 ConnectionBuilder 中可以看到它和 ASP .NET Core 的管道一模一样
有一个 IList 的 _components 的接口
private readonly IList<Func<ConnectionDelegate, ConnectionDelegate>> _components = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
调用 Use 方法的时候就是添加到 _components 中
public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
{
_components.Add(middleware);
return this;
}
最后 Build 的时候进行一下反转
public ConnectionDelegate Build()
{
ConnectionDelegate app = features =>
{
return Task.CompletedTask;
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
KestrelServerImpl 的 UseHttpServer 方法由 options 调用
options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);
虽然它是 ListenOptions,但是其实是一个 ConnectionBuilder
public class ListenOptions : IConnectionBuilder, IMultiplexedConnectionBuilder
它有一个 _middleware 的 List
internal readonly List<Func<ConnectionDelegate, ConnectionDelegate>> _middleware = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
调用 Use 方法的时候,所有中间件会被加入进来
public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
{
_middleware.Add(middleware);
return this;
}
最后调用 Build 的时候,把所有中间件串联起来
public ConnectionDelegate Build()
{
ConnectionDelegate app = context =>
{
return Task.CompletedTask;
};
for (var i = _middleware.Count - 1; i >= 0; i--)
{
var component = _middleware[i];
app = component(app);
}
return app;
}
Build 之后生成 connectionDelegate,传入 _transportManager
options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);
var connectionDelegate = options.Build();
options.EndPoint = await _transportManager.BindAsync(options.EndPoint, connectionDelegate, options.EndpointConfig, onBindCancellationToken).ConfigureAwait(false);
在 _transportManager 绑定的地方可以看到被传入到 StartAcceptLoop 中
StartAcceptLoop(new GenericConnectionListener(transport), c => connectionDelegate(c), endpointConfig);
在 StartAcceptLoop 中绑定到 connectionDispatcher
var connectionDispatcher = new ConnectionDispatcher<T>(_serviceContext, connectionDelegate, transportConnectionManager);
var acceptLoopTask = connectionDispatcher.StartAcceptingConnections(connectionListener);
在 connectionDispatcher 启动的时候,监听请求
var connection = await listener.AcceptAsync();
当有请求过来的时候会将 _connectionDelegate 封装到 KestrelConnection
var kestrelConnection = new KestrelConnection<T>(id, _serviceContext, _transportConnectionManager, _connectionDelegate, connection, Log);
_connectionDelegate 它是一个基于线程池的队列请求的封装,最后 kestrelConnection 会被压入到一个请求队列之中执行
ThreadPool.UnsafeQueueUserWorkItem(kestrelConnection, preferLocal: false);
执行的主要过程可以在 KestrelConnection 中查看,它继承了 IThreadPoolWorkItem,这是一个队列方法
internal class KestrelConnection<T> : KestrelConnection, IThreadPoolWorkItem where T : BaseConnectionContext
在 ExecuteAsync 的时候执行 _connectionDelegate
await _connectionDelegate(connectionContext);
这就是整个 Kestrel 接收到网络请求,后续的全部处理动作
这里也是遵循开闭原则,后面责任链模式可以不断地扩展
同时也体现了关注点分离的原则,确定的部分比如接收网络,字节的部分先处理好,然后不确定的部分通过责任链管道处理
课程链接
https://appsqsyiqlk5791.h5.xiaoeknow.com/v1/course/video/v_5f39bdb8e4b01187873136cf?type=2

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。
如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。
.NET 云原生架构师训练营(责任链模式)--学习笔记的更多相关文章
- .NET 云原生架构师训练营(组合模式)--学习笔记
目录 引入 组合模式 源码 引入 在上一篇执行 _connectionDelegate 之后,HttpConnectionMiddleware 处理请求 return connection.Proce ...
- .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记
目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...
- .NET 云原生架构师训练营(建立系统观)--学习笔记
目录 目标 ASP .NET Core 什么是系统 什么是系统思维 系统分解 什么是复杂系统 作业 目标 通过整体定义去认识系统 通过分解去简化对系统的认识 ASP .NET Core ASP .NE ...
- .NET 云原生架构师训练营(设计原则&&设计模式)--学习笔记
目录 设计原则 设计模式 设计原则 DRY (Don't repeat yourself 不要重复) KISS (Keep it stupid simple 简单到傻子都能看懂) YAGNI (You ...
- .NET 云原生架构师训练营(权限系统 RGCA 架构设计)--学习笔记
目录 项目核心内容 实战目标 RGCA 四步架构法 项目核心内容 无代码埋点实现对所有 API Action 访问控制管理 对 EF Core 实体新增.删除.字段级读写控制管理 与 Identity ...
- .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记
2.7.1 敏捷开发 敏捷介绍 敏捷的起源 敏捷软件开发宣言 敏捷开发十二原则 生命周期对比 敏捷开发的特点 敏捷的发展 敏捷的核心 敏捷的起源 2001年,17个老头子在一起一边滑雪,一边讨论工作, ...
- .NET 云原生架构师训练营(设计原则与模式)--学习笔记
在复杂系统的架构设计中引入设计原则与模式,能够极大降低复杂系统开发.和维护的成本 目录 几个问题 为什么要学习设计模式 优良架构设计的具体指标 理解复杂系统 面向对象思想(指导复杂系统的分析.设计.实 ...
- .NET 云原生架构师训练营(系统架构)--学习笔记
目录 对外展现的功能 内部功能 功能交互与价值通路 系统架构 目标 认识系统的价值通路 认识功能架构,通过把功能结构与形式结构结合来描述系统架构 受益原则 好的架构必须使人受益,要想把架构做好,就要专 ...
- .NET 云原生架构师训练营(对象过程建模)--学习笔记
目录 UML OPM OPM优化 UML 1997年发布UML标准 主要域 视图 图 主要概念 结构 静态视图 类图 类.关联.泛化.依赖关系.实现.接口 用例视图 用例图 用例.参与者.关联.扩展. ...
随机推荐
- 【力扣】123. 买卖股票的最佳时机 III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你最多可以完成 两笔 交易. 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的 ...
- JavaOOP对象和封装
对象: 前言: 在程序员眼中,世界万物皆为对象.世界上有两种人,一种是懂二进制的人,一种就是不懂二进制的人. 面向对象设计的过程就是抽象的过程. 步骤: 第一步:发现类 第二步:发现类的属性 第三步: ...
- Jenkins性能测试
目录 一.简介 二.JMeter测试 一.简介 Taurus是-个开源的自动化框架,用于运行各种开源负载测试工具和功能测试工具.其支持最流行的开源负载测试工具Apache JMeter.Seleniu ...
- 【js基础】基础数据类型变量为啥有属性?
1.变量和数值 let a =1 这是一个简单的变量声明,其中"a"是变量,在代码中供程序员或者语法操作的,而1是数值,是我最终需要的东西.为什么不直接使用数值而使用变量?这个就不 ...
- Excel的内置功能,其实真的是够用了。(学习观)
很多人问我,学好Excel是不是要背好多函数,是不是要会写VBA代码? 我说,那得看你能放多少时间和精力在Excel上. Excel的内置功能,其实真的是够用了:觉得不够用的,花几十块钱买个插件,也差 ...
- manjaro(arch系)Linux使用(一)
# manjaro的使用 ## 配置源 先切换国内的镜像源仓库 `sudo pacman-mirrors -i -c China -m rank` 在弹出的窗口中选择延迟最小的源 ### 添加arch ...
- Django记录操作日志、LogEntry的使用
LogEntry是在后台开发中经常用到的模块,它在admin是默认开启的. 可以使用LogEntry模块记录所有用户的操作记录.一方面可以用来监督,另一方面可以用来做回滚. 1. 使用LogEntry ...
- LuoguP7505 「Wdsr-2.5」小小的埴轮兵团 题解
Content 给出一个范围为 \([-k,k]\) 的数轴,数轴上有 \(n\) 个点,第 \(i\) 个点的位置为 \(a_i\).有 \(m\) 次操作,有且仅有以下三种: 1 x:所有点往右移 ...
- jQuery实现页面导航内容定位效果,并支持内容切换
需求 页面向下滚动时,需要将顶部的搜索栏信息和导航菜单吸顶,并且,搜索栏信息和导航菜单之间可以切换. 效果 https://www.iguopin.com/index.php?m=&c=ind ...
- Windows的Nginx服务可视化界面安装
先安装Nginx服务 启动 Windows安装Nginx服务 参考:https://www.cnblogs.com/pxblog/p/14871932.html 下载软件 https://github ...