天天看點

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

目錄

  • 引入
  • 組合模式
  • 源碼

在上一篇執行 _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();
});
           
.NET 雲原生架構師訓練營(組合模式)--學習筆記

調用 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 進來的時候,會把所有的路由進行分割,從上到下進行比對

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

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 葉子節點的組合

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

課程連結

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

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

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

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

如有任何疑問,請與我聯系 ([email protected]) 。