目录

  • 模板方法
  • 源码
  • 建造者

模板方法

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤

源码

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

在目录 aspnetcore\src\Mvc\Mvc.Core\src\Infrastructure 下有一个 ControllerActionInvoker,它继承自 ResourceInvoker

internal class ControllerActionInvoker : ResourceInvoker, IActionInvoker

在 ResourceInvoker 中定义了一些算法的骨架,在 InvokeAsync 方法中对一些方法进行了组装

public virtual Task InvokeAsync()
{
...
task = InvokeFilterPipelineAsync();
...
return ReleaseResourcesCore(scope).AsTask();
...
}

还有一些抽象方法需要在子类 ControllerActionInvoker 中实现

/// <summary>
/// In derived types, releases resources such as controller, model, or page instances created as
/// part of invoking the inner pipeline.
/// </summary>
protected abstract ValueTask ReleaseResources(); protected abstract Task InvokeInnerFilterAsync();

这里就是模板方法的一个应用,通过抽象类和一个子类来实现

子类没有 InvokeAsync 方法,它在顶层完成了封装,对多个方法进行调用,同时提供一些中间联合的方法

从 MapControllers 方法的角度看,调用了 ControllerEndpointRouteBuilderExtensions

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

ControllerEndpointRouteBuilderExtensions 这个类会告诉你整个注册的过程发生了什么

首先,它接收了一个 IEndpointRouteBuilder

public static ControllerActionEndpointConventionBuilder MapControllers(this IEndpointRouteBuilder endpoints)
{
... EnsureControllerServices(endpoints); return GetOrCreateDataSource(endpoints).DefaultBuilder;
}

在 EnsureControllerServices 中把所有的服务获取进来

var marker = endpoints.ServiceProvider.GetService<MvcMarkerService>();

MvcMarkerService 需要先注册,获取 DataSources,然后注册

private static ControllerActionEndpointDataSource GetOrCreateDataSource(IEndpointRouteBuilder endpoints)
{
var dataSource = endpoints.DataSources.OfType<ControllerActionEndpointDataSource>().FirstOrDefault();
if (dataSource == null)
{
var orderProvider = endpoints.ServiceProvider.GetRequiredService<OrderedEndpointsSequenceProviderCache>();
var factory = endpoints.ServiceProvider.GetRequiredService<ControllerActionEndpointDataSourceFactory>();
dataSource = factory.Create(orderProvider.GetOrCreateOrderedEndpointsSequenceProvider(endpoints));
endpoints.DataSources.Add(dataSource);
} return dataSource;
}

在 ControllerActionEndpointDataSource 中遍历 actions

for (var i = 0; i < actions.Count; i++)
{
if (actions[i] is ControllerActionDescriptor action)
{
_endpointFactory.AddEndpoints(endpoints, routeNames, action, _routes, conventions, CreateInertEndpoints);

这些 actions 来自于基类 ActionEndpointDataSourceBase

public ActionEndpointDataSourceBase(IActionDescriptorCollectionProvider actions)
{
_actions = actions; Conventions = new List<Action<EndpointBuilder>>();
}

actions 通过 CreateEndpoints 绑定到 RequestDelegate

protected override List<Endpoint> CreateEndpoints(IReadOnlyList<ActionDescriptor> actions, IReadOnlyList<Action<EndpointBuilder>> conventions)

CreateEndpoints 中有一个 AddEndpoints 方法

_endpointFactory.AddEndpoints(endpoints, routeNames, action, _routes, conventions, CreateInertEndpoints);

在 AddEndpoints 方法中将一个 action 转换为一个 endpoint

var builder = new InertEndpointBuilder()
{
DisplayName = action.DisplayName,
RequestDelegate = _requestDelegate,
};
AddActionDataToBuilder(
builder,
routeNames,
action,
routeName: null,
dataTokens: null,
suppressLinkGeneration: false,
suppressPathMatching: false,
conventions,
Array.Empty<Action<EndpointBuilder>>());
endpoints.Add(builder.Build());

接着看一下 _requestDelegate

_requestDelegate = CreateRequestDelegate();

这里才是真正执行每个 web api 请求的入口

private static RequestDelegate CreateRequestDelegate()
{
// We don't want to close over the Invoker Factory in ActionEndpointFactory as
// that creates cycles in DI. Since we're creating this delegate at startup time
// we don't want to create all of the things we use at runtime until the action
// actually matches.
//
// The request delegate is already a closure here because we close over
// the action descriptor.
IActionInvokerFactory? invokerFactory = null; return (context) =>
{
var endpoint = context.GetEndpoint()!;
var dataTokens = endpoint.Metadata.GetMetadata<IDataTokensMetadata>(); var routeData = new RouteData();
routeData.PushState(router: null, context.Request.RouteValues, new RouteValueDictionary(dataTokens?.DataTokens)); // Don't close over the ActionDescriptor, that's not valid for pages.
var action = endpoint.Metadata.GetMetadata<ActionDescriptor>()!;
var actionContext = new ActionContext(context, routeData, action); if (invokerFactory == null)
{
invokerFactory = context.RequestServices.GetRequiredService<IActionInvokerFactory>();
} var invoker = invokerFactory.CreateInvoker(actionContext);
return invoker!.InvokeAsync();
};
}

首先从 context 获取 endpoint,接着从 endpoint 得到 ActionDescriptor,再将它封装成一个 ActionContext

通过 invokerFactory 创建一个 invoker,最后调用 InvokeAsync,所以整个执行过程是一个委托,在执行 MapControllers 的时候已经将委托挂到整个执行的 endpoint

每个路由的 endpoint 最后都是指向同一个地方,全部指向同一个 Delegate,只不过这个 Delegate 从 endpoint 的 Metadata 中拿到的 action 的定义,包括 controller, method, parameter

最后通过 invoker 的形式调用,所以才用到了 ResourceInvoker, PageActionInvoker, 和 ControllerActionInvoker 三种方式,发挥了模板方法作用

建造者

它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成

它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的

建造者和模板方法有点类似,一个属于行为型的设计模式,一个属于创建型的设计模式

模板方法强调的是行为上面的分解,建造者更加关注创建对象的分解

两者都是基于一个抽象的类提供抽象方法交给具体的类实现,代码类似,意义不同

课程链接

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

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

.NET 云原生架构师训练营(模板方法 && 建造者)--学习笔记的更多相关文章

  1. .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记

    目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...

  2. .NET 云原生架构师训练营(建立系统观)--学习笔记

    目录 目标 ASP .NET Core 什么是系统 什么是系统思维 系统分解 什么是复杂系统 作业 目标 通过整体定义去认识系统 通过分解去简化对系统的认识 ASP .NET Core ASP .NE ...

  3. .NET 云原生架构师训练营(权限系统 RGCA 架构设计)--学习笔记

    目录 项目核心内容 实战目标 RGCA 四步架构法 项目核心内容 无代码埋点实现对所有 API Action 访问控制管理 对 EF Core 实体新增.删除.字段级读写控制管理 与 Identity ...

  4. .NET 云原生架构师训练营(设计原则&&设计模式)--学习笔记

    目录 设计原则 设计模式 设计原则 DRY (Don't repeat yourself 不要重复) KISS (Keep it stupid simple 简单到傻子都能看懂) YAGNI (You ...

  5. .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记

    2.7.1 敏捷开发 敏捷介绍 敏捷的起源 敏捷软件开发宣言 敏捷开发十二原则 生命周期对比 敏捷开发的特点 敏捷的发展 敏捷的核心 敏捷的起源 2001年,17个老头子在一起一边滑雪,一边讨论工作, ...

  6. .NET 云原生架构师训练营(设计原则与模式)--学习笔记

    在复杂系统的架构设计中引入设计原则与模式,能够极大降低复杂系统开发.和维护的成本 目录 几个问题 为什么要学习设计模式 优良架构设计的具体指标 理解复杂系统 面向对象思想(指导复杂系统的分析.设计.实 ...

  7. .NET 云原生架构师训练营(系统架构)--学习笔记

    目录 对外展现的功能 内部功能 功能交互与价值通路 系统架构 目标 认识系统的价值通路 认识功能架构,通过把功能结构与形式结构结合来描述系统架构 受益原则 好的架构必须使人受益,要想把架构做好,就要专 ...

  8. .NET 云原生架构师训练营(对象过程建模)--学习笔记

    目录 UML OPM OPM优化 UML 1997年发布UML标准 主要域 视图 图 主要概念 结构 静态视图 类图 类.关联.泛化.依赖关系.实现.接口 用例视图 用例图 用例.参与者.关联.扩展. ...

  9. .NET 云原生架构师训练营(ASP .NET Core 整体概念推演)--学习笔记

    演化与完善整体概念 ASP .NET Core 整体概念推演 整体概念推演到具体的形式 ASP .NET Core 整体概念推演 ASP .NET Core 其实就是通过 web framework ...

随机推荐

  1. JPA和事务管理

    JPA和事务管理 很重要的一点是JPA本身并不提供任何类型的声明式事务管理.如果在依赖注入容器之外使用JPA,事务处理必须由开发人员编程实现. 123456789101112UserTransacti ...

  2. 【Linux卷管理】LVM创建与管理

    安装LVM 首先确定系统中是否安装了lvm工具: [root@jetsen ~]# rpm -qa|grep lvm system-config-lvm-1.1.5-1.0.el5 lvm2-2.02 ...

  3. 安全刻不容缓「GitHub 热点速览 v.21.50」

    作者:HelloGitHub-小鱼干 本周最热的事件莫过于 Log4j 漏洞,攻击者仅需向目标输入一段代码,不需要用户执行任何多余操作即可触发该漏洞,使攻击者可以远程控制用户受害者服务器,90% 以上 ...

  4. 华为云函数中使用云数据库的JavaScript SDK基础入门

    背景介绍 使用云数据库Server端的SDK,此处我以华为提供的官方Demo为例,他们的Demo也已经开源放在了GitHub上,大家需要的可以自行下载. https://github.com/AppG ...

  5. python3.6.4 scrapy框架from PIL import Image报错 from . import _imaging as core

    scrapy框架爬取url下载图片时,用ImagesPipeline下载图片 from PIL import Image报错 from . import _imaging as core Import ...

  6. pipeline option指令

    目录 一.简介 二.参数 buildDiscarder checkoutToSubdirectory disableConcurrentBuilds newContainerPerStage retr ...

  7. [Java Web 王者归来]读书笔记3

    第四章 JSP JSP基本语法 1 JSP中嵌入Java 代码 <% Java code %> 2 JSP中输出 <%= num %> 3 JSP 中的注释 <%-- - ...

  8. [BUUCTF]PWN——roarctf_2019_easy_pwn(详解)

    roarctf_2019_easy_pwn 附件 步骤: 例行检查,64位程序,保护全开 试运行一下程序,看看大概的情况,经典的堆块的菜单 64位ida载入,改了一下各个选项的函数名,方便看程序(按N ...

  9. [BUUCTF]PWN——jarvisoj_level1

    jarvisoj_level1 附件 步骤: 例行检查,32位程序,没有开任何保护 本地运行一下程序,看看大概的情况,可以看到输出了一个地址 32位ida载入,习惯性的检索程序里的字符串,没有发现可以 ...

  10. CF1036A Function Height 题解

    Content 给定一个坐标系,在它的 \(x\) 轴上有 \(2n+1\) 个点 \(P_0,P_1,P_2,...,P_{2n}\),其中对于 \(0\leqslant i\leqslant 2n ...