ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-05 20:04:42  阅读:211  来源: 互联网

标签:return 请求 -- middleware connectionDelegate var 架构师 NET options


目录

  • 责任链模式
  • 源码

责任链模式

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

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

使用场景:

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

源码

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) 。

标签:return,请求,--,middleware,connectionDelegate,var,架构师,NET,options
来源: https://www.cnblogs.com/MingsonZheng/p/15768621.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有