.NET 雲原生架構師訓練營(組合模式)--學習筆記

MingsonZheng發表於2022-01-06

目錄

  • 引入
  • 組合模式
  • 原始碼

引入

在上一篇執行 _connectionDelegate 之後,HttpConnectionMiddleware 處理請求

return connection.ProcessRequestsAsync(_application);

在 HttpConnection 中呼叫 IRequestProcessor 的 ProcessRequestsAsync 方法

await requestProcessor.ProcessRequestsAsync(httpApplication);

跳轉到 IRequestProcessor 的實現類 HttpProtocol 的 ProcessRequests 方法

private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application) where TContext : notnull

這裡會建立 MessageBody

var messageBody = CreateMessageBody();

然後建立一個真正的 context,這個時候 context 就被轉換成一個可讀的 HTTPContext

var context = application.CreateContext(this);

接著開始真正的呼叫 HTTPApplication,走到 Host 裡面,接著執行 startup 裡面寫的管道

// Run the application code for this request
await application.ProcessRequestAsync(context);

那麼接下來的 controller,api 如何出來呢?

通過 routing 和 endpoints,每個請求會 map 到一個 endpoint

app.UseRouting();

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

呼叫 UseRouting 之後會新增一個 EndpointRoutingMiddleware,用於匹配路由,會將一個 URL 匹配到一個 Endpoint

MapControllers 會掃描所有 api 上面的路由,新增到 DataSource 中,它被 EndpointDataSource 所使用

由於 DataSource 的存在,可以找到匹配,匹配之後會將 SelectEndpoint 掛到 HttpContext

而 Endpoint 中是一個 RequestDelegate

如果不使用 Route 和 Endpoint,可以使用這樣的形式

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

internal sealed partial class DfaMatcher : Matcher

DfaMatcher 有一個 MatchAsync 方法

public sealed override Task MatchAsync(HttpContext httpContext)

在 MatchAsync 方法裡面首先拿到 path,接著查詢候選集

var path = httpContext.Request.Path.Value!;

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

FindCandidateSet 方法裡面有已經構造好的 DfaState,包含了路由分割資訊

private readonly DfaState[] _states;

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

DfaMatcherBuilder 有一個 Build 方法

public override Matcher Build()

在 Build 方法裡面 BuildDfaTree

var root = BuildDfaTree(includeLabel);

BuildDfaTree 由很多個 Node 組成

AddNode(root, states, exitDestination);

然後構建 DfaState

states[exitDestination] = new DfaState(
    Array.Empty<Candidate>(),
    Array.Empty<IEndpointSelectorPolicy>(),
    JumpTableBuilder.Build(exitDestination, exitDestination, null),
    null);

再把 DfaState 傳給 DfaMatcher

return new DfaMatcher(_loggerFactory.CreateLogger<DfaMatcher>(), _selector, states, maxSegmentCount);

由於這個過程比較複雜,所以將這個過程包裝在 DataSourceDependentMatcher,但是它不是一個 Matcher

DataSourceDependentMatcher 的 MatchAsync 方法直接呼叫了 CurrentMatcher 的 MatchAsync 方法

public override Task MatchAsync(HttpContext httpContext)
{
    return CurrentMatcher.MatchAsync(httpContext);
}

所以 DataSourceDependentMatcher 的主要功能是構造一個 Matcher,就是一個 DfaMatcher

private Matcher CreateMatcher(IReadOnlyList<Endpoint> endpoints)

對外部來講只是一個 Matcher,然後它需要實現對內部的封裝,把所有細節隱藏在 DataSourceDependentMatcher 中

DataSourceDependentMatcher 只是一個對 DfaMatcher 葉子節點的組合

課程連結

https://appsqsyiqlk5791.h5.xiaoeknow.com/v1/course/video/v_5f39bdb8e4b01187873136cf?type=2

知識共享許可協議

本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。

歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含連結: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。

如有任何疑問,請與我聯絡 (MingsonZheng@outlook.com) 。

相關文章