目录

  • 责任链模式
  • 源码

责任链模式

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无需关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了

何时使用:在处理消息的时候以过滤很多道

使用场景:

  • 有多个对象可以处理同一个请求,具体到哪个对象处理该请求由运行时刻自动确定
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
  • 可动态指定一组对象处理请求

源码

https://github.com/dotnet/aspnetcore/

在 ASP .NET Core 源码的 Kestrel 当中,构建 KestrelConnection 之后传送给 HttpConnectionMiddleware 中间件处理管道

在目录 Microsoft.AspNetCore.Server.Kestrel.Core 下面的 KestrelServerImpl 中有一个 UseHttpServer 方法

  1. options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);

在 UseHttpServer 方法中构造了一个 HttpConnectionMiddleware,构造之后调用了 IConnectionBuilder 的 Use 方法

  1. public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols, bool addAltSvcHeader) where TContext : notnull
  2. {
  3. var middleware = new HttpConnectionMiddleware<TContext>(serviceContext, application, protocols, addAltSvcHeader);
  4. return builder.Use(next =>
  5. {
  6. return middleware.OnConnectionAsync;
  7. });
  8. }

在 IConnectionBuilder 的实现类 ConnectionBuilder 中可以看到它和 ASP .NET Core 的管道一模一样

有一个 IList 的 _components 的接口

  1. private readonly IList<Func<ConnectionDelegate, ConnectionDelegate>> _components = new List<Func<ConnectionDelegate, ConnectionDelegate>>();

调用 Use 方法的时候就是添加到 _components 中

  1. public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
  2. {
  3. _components.Add(middleware);
  4. return this;
  5. }

最后 Build 的时候进行一下反转

  1. public ConnectionDelegate Build()
  2. {
  3. ConnectionDelegate app = features =>
  4. {
  5. return Task.CompletedTask;
  6. };
  7. foreach (var component in _components.Reverse())
  8. {
  9. app = component(app);
  10. }
  11. return app;
  12. }

KestrelServerImpl 的 UseHttpServer 方法由 options 调用

  1. options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);

虽然它是 ListenOptions,但是其实是一个 ConnectionBuilder

  1. public class ListenOptions : IConnectionBuilder, IMultiplexedConnectionBuilder

它有一个 _middleware 的 List

  1. internal readonly List<Func<ConnectionDelegate, ConnectionDelegate>> _middleware = new List<Func<ConnectionDelegate, ConnectionDelegate>>();

调用 Use 方法的时候,所有中间件会被加入进来

  1. public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
  2. {
  3. _middleware.Add(middleware);
  4. return this;
  5. }

最后调用 Build 的时候,把所有中间件串联起来

  1. public ConnectionDelegate Build()
  2. {
  3. ConnectionDelegate app = context =>
  4. {
  5. return Task.CompletedTask;
  6. };
  7. for (var i = _middleware.Count - 1; i >= 0; i--)
  8. {
  9. var component = _middleware[i];
  10. app = component(app);
  11. }
  12. return app;
  13. }

Build 之后生成 connectionDelegate,传入 _transportManager

  1. options.UseHttpServer(ServiceContext, application, options.Protocols, addAltSvcHeader);
  2. var connectionDelegate = options.Build();
  3. options.EndPoint = await _transportManager.BindAsync(options.EndPoint, connectionDelegate, options.EndpointConfig, onBindCancellationToken).ConfigureAwait(false);

在 _transportManager 绑定的地方可以看到被传入到 StartAcceptLoop 中

  1. StartAcceptLoop(new GenericConnectionListener(transport), c => connectionDelegate(c), endpointConfig);

在 StartAcceptLoop 中绑定到 connectionDispatcher

  1. var connectionDispatcher = new ConnectionDispatcher<T>(_serviceContext, connectionDelegate, transportConnectionManager);
  2. var acceptLoopTask = connectionDispatcher.StartAcceptingConnections(connectionListener);

在 connectionDispatcher 启动的时候,监听请求

  1. var connection = await listener.AcceptAsync();

当有请求过来的时候会将 _connectionDelegate 封装到 KestrelConnection

  1. var kestrelConnection = new KestrelConnection<T>(id, _serviceContext, _transportConnectionManager, _connectionDelegate, connection, Log);

_connectionDelegate 它是一个基于线程池的队列请求的封装,最后 kestrelConnection 会被压入到一个请求队列之中执行

  1. ThreadPool.UnsafeQueueUserWorkItem(kestrelConnection, preferLocal: false);

执行的主要过程可以在 KestrelConnection 中查看,它继承了 IThreadPoolWorkItem,这是一个队列方法

  1. internal class KestrelConnection<T> : KestrelConnection, IThreadPoolWorkItem where T : BaseConnectionContext

在 ExecuteAsync 的时候执行 _connectionDelegate

  1. 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 云原生架构师训练营(责任链模式)--学习笔记的更多相关文章

  1. .NET 云原生架构师训练营(组合模式)--学习笔记

    目录 引入 组合模式 源码 引入 在上一篇执行 _connectionDelegate 之后,HttpConnectionMiddleware 处理请求 return connection.Proce ...

  2. .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记

    目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...

  3. .NET 云原生架构师训练营(建立系统观)--学习笔记

    目录 目标 ASP .NET Core 什么是系统 什么是系统思维 系统分解 什么是复杂系统 作业 目标 通过整体定义去认识系统 通过分解去简化对系统的认识 ASP .NET Core ASP .NE ...

  4. .NET 云原生架构师训练营(设计原则&&设计模式)--学习笔记

    目录 设计原则 设计模式 设计原则 DRY (Don't repeat yourself 不要重复) KISS (Keep it stupid simple 简单到傻子都能看懂) YAGNI (You ...

  5. .NET 云原生架构师训练营(权限系统 RGCA 架构设计)--学习笔记

    目录 项目核心内容 实战目标 RGCA 四步架构法 项目核心内容 无代码埋点实现对所有 API Action 访问控制管理 对 EF Core 实体新增.删除.字段级读写控制管理 与 Identity ...

  6. .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记

    2.7.1 敏捷开发 敏捷介绍 敏捷的起源 敏捷软件开发宣言 敏捷开发十二原则 生命周期对比 敏捷开发的特点 敏捷的发展 敏捷的核心 敏捷的起源 2001年,17个老头子在一起一边滑雪,一边讨论工作, ...

  7. .NET 云原生架构师训练营(设计原则与模式)--学习笔记

    在复杂系统的架构设计中引入设计原则与模式,能够极大降低复杂系统开发.和维护的成本 目录 几个问题 为什么要学习设计模式 优良架构设计的具体指标 理解复杂系统 面向对象思想(指导复杂系统的分析.设计.实 ...

  8. .NET 云原生架构师训练营(系统架构)--学习笔记

    目录 对外展现的功能 内部功能 功能交互与价值通路 系统架构 目标 认识系统的价值通路 认识功能架构,通过把功能结构与形式结构结合来描述系统架构 受益原则 好的架构必须使人受益,要想把架构做好,就要专 ...

  9. .NET 云原生架构师训练营(对象过程建模)--学习笔记

    目录 UML OPM OPM优化 UML 1997年发布UML标准 主要域 视图 图 主要概念 结构 静态视图 类图 类.关联.泛化.依赖关系.实现.接口 用例视图 用例图 用例.参与者.关联.扩展. ...

随机推荐

  1. RTTI (Run-time type information) in C++

    In C++, RTTI (Run-time type information) is available only for the classes which have at least one v ...

  2. Advanced C++ | Virtual Constructor

    Can we make a class constructor virtual in C++ to create polymorphic objects? No. C++ being static t ...

  3. Dubbo中CompletableFuture异步调用

    使用Future实现异步调用,对于无需获取返回值的操作来说不存在问题,但消费者若需要获取到最终的异步执行结果,则会出现问题:消费者在使用Future的get()方法获取返回值时被阻塞.为了解决这个问题 ...

  4. React 传值 组件传值 之间的关系

    react 组件相互之间的传值: 传值分父级组件传值给子组件   子组件传值给父组件    平级组件.没有嵌套的组件相互传值 1.父组件向子组件传值 父组件通过属性的形式来向子组件传值,子组件通过pr ...

  5. Nginx+ uWSGI +django进行部署

    一:uWSGI的安装 sudo pip install uwsgi 如果安装报错: conda install -c conda-forge uwsgi conda install -c conda- ...

  6. MySQL获取对应时间

    一.查询当前时间包含年月日 SELECT CURDATE(); SELECT CURRENT_DATE(); 二.查询当前时间包含年月日时分秒 SELECT NOW(); SELECT SYSDATE ...

  7. 『忘了再学』Shell基础 — 1、Shell的介绍

    目录 1.Shell的由来 2.Shell的两种执行指令方式 3.什么是Shell脚本 4.Shell 是一种脚本语言 1.Shell的由来 我们比较熟悉Windows系统的图形化界面,对于图形界面来 ...

  8. mapbox获取各种经纬度

    点击地图即可获取经纬度,也可以手动输入经纬度来换算 在线查看运行效果 实现方法 mapbox中通过地图点击事件来获取到坐标,然后转换为其他的坐标系并输出在屏幕上即可 获取坐标 方法很简单,给地图添加一 ...

  9. CF31B Sysadmin Bob 题解

    Content 给定一个字符串 \(s\),请将其分解为诸如 \(\texttt{xx@xx}\) 的子串,并将分解后的所有子串输出,或者说不存在这样的方案. 数据范围:\(1\leqslant|s| ...

  10. java 图形化小工具Abstract Window Toolit ;布局管理器FlowLayout流式布局;BorderLayout边界布局;GridLayout网格布局;CardLayou重叠卡片布局;BoxLayout方框布局;绝对定位

    1.FlowLayout流式布局管理器: FlowLayout布局管理器中,组件像水流一样向某方向流动(排列),遇到障碍(边界)就折回,重头开始排列 .在默认情况下,FlowLayout局管理器从左向 ...