# 责任链模式

## 目录 <a href="#mu-lu" id="mu-lu"></a>

* 责任链模式
* 源码

### 责任链模式 <a href="#ze-ren-lian-mo-shi" id="ze-ren-lian-mo-shi"></a>

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FoPey8muyXWct4Vt2VPsn%2F301.jpg?alt=media\&token=24460259-bfa8-4d09-a2c6-74089b1f8812)

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

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

使用场景：

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

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FP6Fj0wKVisvNYDqTxG3P%2F302.jpg?alt=media\&token=b5553979-f463-4f63-abf8-7d4ffe346297)

### 源码 <a href="#yuan-ma" id="yuan-ma"></a>

<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 接收到网络请求，后续的全部处理动作

这里也是遵循开闭原则，后面责任链模式可以不断地扩展

同时也体现了关注点分离的原则，确定的部分比如接收网络，字节的部分先处理好，然后不确定的部分通过责任链管道处理
