前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET 云原生架构师训练营(组合模式)--学习笔记

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

原创
作者头像
郑子铭
发布2022-01-06 23:15:28
3480
发布2022-01-06 23:15:28
举报

目录

  • 引入
  • 组合模式
  • 源码

引入

在上一篇执行 _connectionDelegate 之后,HttpConnectionMiddleware 处理请求

代码语言:javascript
复制
return connection.ProcessRequestsAsync(_application);

在 HttpConnection 中调用 IRequestProcessor 的 ProcessRequestsAsync 方法

代码语言:javascript
复制
await requestProcessor.ProcessRequestsAsync(httpApplication);

跳转到 IRequestProcessor 的实现类 HttpProtocol 的 ProcessRequests 方法

代码语言:javascript
复制
private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application) where TContext : notnull

这里会创建 MessageBody

代码语言:javascript
复制
var messageBody = CreateMessageBody();

然后创建一个真正的 context,这个时候 context 就被转换成一个可读的 HTTPContext

代码语言:javascript
复制
var context = application.CreateContext(this);

接着开始真正的调用 HTTPApplication,走到 Host 里面,接着执行 startup 里面写的管道

代码语言:javascript
复制
// Run the application code for this request
await application.ProcessRequestAsync(context);

那么接下来的 controller,api 如何出来呢?

通过 routing 和 endpoints,每个请求会 map 到一个 endpoint

代码语言:javascript
复制
app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

调用 UseRouting 之后会添加一个 EndpointRoutingMiddleware,用于匹配路由,会将一个 URL 匹配到一个 Endpoint

MapControllers 会扫描所有 api 上面的路由,添加到 DataSource 中,它被 EndpointDataSource 所使用

由于 DataSource 的存在,可以找到匹配,匹配之后会将 SelectEndpoint 挂到 HttpContext

而 Endpoint 中是一个 RequestDelegate

如果不使用 Route 和 Endpoint,可以使用这样的形式

代码语言:javascript
复制
app.Run(async context => { await context.Response.WriteAsync("aaa"); });

在匹配的时候我们用到了组合的设计模式

组合模式

将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性

组合模式(Composite)经常用于树形结构,为了简化代码,使用Composite可以把一个叶子节点与一个父节点统一起来处理

Route DfaNode:通过遍历的形式,当一个 url 进来的时候,会把所有的路由进行分割,从上到下进行匹配

源码

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

在目录 Microsoft.AspNetCore.Routing.Matching 下面有一个 DfaMatcher,它继承自 Matcher

代码语言:javascript
复制
internal sealed partial class DfaMatcher : Matcher

DfaMatcher 有一个 MatchAsync 方法

代码语言:javascript
复制
public sealed override Task MatchAsync(HttpContext httpContext)

在 MatchAsync 方法里面首先拿到 path,接着查找候选集

代码语言:javascript
复制
var path = httpContext.Request.Path.Value!;

var (candidates, policies) = FindCandidateSet(httpContext, path, segments);

FindCandidateSet 方法里面有已经构造好的 DfaState,包含了路由分割信息

代码语言:javascript
复制
private readonly DfaState[] _states;

在进行 Match 之前需要有一个 DfaTree,可以在 DfaMatcherBuilder 中找到

DfaMatcherBuilder 有一个 Build 方法

代码语言:javascript
复制
public override Matcher Build()

在 Build 方法里面 BuildDfaTree

代码语言:javascript
复制
var root = BuildDfaTree(includeLabel);

BuildDfaTree 由很多个 Node 组成

代码语言:javascript
复制
AddNode(root, states, exitDestination);

然后构建 DfaState

代码语言:javascript
复制
states[exitDestination] = new DfaState(
    Array.Empty<Candidate>(),
    Array.Empty<IEndpointSelectorPolicy>(),
    JumpTableBuilder.Build(exitDestination, exitDestination, null),
    null);

再把 DfaState 传给 DfaMatcher

代码语言:javascript
复制
return new DfaMatcher(_loggerFactory.CreateLogger<DfaMatcher>(), _selector, states, maxSegmentCount);

由于这个过程比较复杂,所以将这个过程包装在 DataSourceDependentMatcher,但是它不是一个 Matcher

DataSourceDependentMatcher 的 MatchAsync 方法直接调用了 CurrentMatcher 的 MatchAsync 方法

代码语言:javascript
复制
public override Task MatchAsync(HttpContext httpContext)
{
    return CurrentMatcher.MatchAsync(httpContext);
}

所以 DataSourceDependentMatcher 的主要功能是构造一个 Matcher,就是一个 DfaMatcher

代码语言:javascript
复制
private Matcher CreateMatcher(IReadOnlyList<Endpoint> endpoints)

对外部来讲只是一个 Matcher,然后它需要实现对内部的封装,把所有细节隐藏在 DataSourceDependentMatcher 中

DataSourceDependentMatcher 只是一个对 DfaMatcher 叶子节点的组合

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
    • 引入
      • 组合模式
        • 源码
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档