.NET 云原生架构师训练营(模板方法 && 建造者)--学习笔记
目录
- 模板方法
- 源码
- 建造者
模板方法
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
源码
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 云原生架构师训练营(模板方法 && 建造者)--学习笔记的更多相关文章
- .NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记
目录 什么是软件架构 软件架构的基本思路 单体向分布式演进.云原生.技术中台 1.1 什么是软件架构 1.1.1 什么是架构? Software architecture = {Elements, F ...
- .NET 云原生架构师训练营(建立系统观)--学习笔记
目录 目标 ASP .NET Core 什么是系统 什么是系统思维 系统分解 什么是复杂系统 作业 目标 通过整体定义去认识系统 通过分解去简化对系统的认识 ASP .NET Core ASP .NE ...
- .NET 云原生架构师训练营(权限系统 RGCA 架构设计)--学习笔记
目录 项目核心内容 实战目标 RGCA 四步架构法 项目核心内容 无代码埋点实现对所有 API Action 访问控制管理 对 EF Core 实体新增.删除.字段级读写控制管理 与 Identity ...
- .NET 云原生架构师训练营(设计原则&&设计模式)--学习笔记
目录 设计原则 设计模式 设计原则 DRY (Don't repeat yourself 不要重复) KISS (Keep it stupid simple 简单到傻子都能看懂) YAGNI (You ...
- .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记
2.7.1 敏捷开发 敏捷介绍 敏捷的起源 敏捷软件开发宣言 敏捷开发十二原则 生命周期对比 敏捷开发的特点 敏捷的发展 敏捷的核心 敏捷的起源 2001年,17个老头子在一起一边滑雪,一边讨论工作, ...
- .NET 云原生架构师训练营(设计原则与模式)--学习笔记
在复杂系统的架构设计中引入设计原则与模式,能够极大降低复杂系统开发.和维护的成本 目录 几个问题 为什么要学习设计模式 优良架构设计的具体指标 理解复杂系统 面向对象思想(指导复杂系统的分析.设计.实 ...
- .NET 云原生架构师训练营(系统架构)--学习笔记
目录 对外展现的功能 内部功能 功能交互与价值通路 系统架构 目标 认识系统的价值通路 认识功能架构,通过把功能结构与形式结构结合来描述系统架构 受益原则 好的架构必须使人受益,要想把架构做好,就要专 ...
- .NET 云原生架构师训练营(对象过程建模)--学习笔记
目录 UML OPM OPM优化 UML 1997年发布UML标准 主要域 视图 图 主要概念 结构 静态视图 类图 类.关联.泛化.依赖关系.实现.接口 用例视图 用例图 用例.参与者.关联.扩展. ...
- .NET 云原生架构师训练营(ASP .NET Core 整体概念推演)--学习笔记
演化与完善整体概念 ASP .NET Core 整体概念推演 整体概念推演到具体的形式 ASP .NET Core 整体概念推演 ASP .NET Core 其实就是通过 web framework ...
随机推荐
- 页面屏蔽backspace键
1 //页面加载完成 2 $(document).ready(function(){ 3 //禁止退格键 作用于Firefox.Opera 4 document.onkeypress = banBac ...
- 删除数据库时报错 ERROR 1010 (HY000): Error dropping database (can't rmdir './cart', errno: 39)
这是因为在数据目录下有表相关的数据(不是表),此时应该进入存放表的目录下删除与表相关的数据,一般数据存放目录默认为/var/lib/mysql,cd到目录下 执行命令:cd /var/lib/mysq ...
- 3.2 go WaitGroup代码示例
sync.WaitGroup提供了一种安全的多协程处理方法,内部使用race.atomic来处理,避免了资源竞争及锁的产生. 主要的方法有Add.Done.Wait,可以等待一组协程全部执行完毕后,主 ...
- apply 和 call 的区别
相同点: 都能够改变方法的执行上下文(执行环境),将一个对象的方法交给另一个对象来执行,并且是立即执行 不同点: call方法从第二个参数开始可以接收任意个参数,每个参数会映射到相应位置的func的参 ...
- 在vue3中使用router-link-active遇到的坑
在使用 router-link-active 设置链接激活时CSS类名时,发现在例如 /member/order 和 /member/order/:id 这两个都包含 /member/order的路由 ...
- Winamp栈溢出漏洞研究
Winamp作为一款在90年代最主流的音乐播放器,到现在仍有大量的忠实粉丝.当然也存在很多漏洞.下面具体分析的就是打开软件的更新历史信息而触发的一个缓冲区溢出漏洞. 0X01漏洞重现 正常的whats ...
- IDEA 2021.2.1 破解版下载_激活安装图文教程(永久激活,亲测有效)
1.IntelliJ IDEA 2021 链接:https://pan.baidu.com/s/1Pwz3GrrkJdDZzg-wg5UjMw 提取码:56o6 无限重置 30 天试用期补丁 链接:h ...
- 卸载zabbix
1.首先停止zabbix运行 可以用官方命令 systemctl stop zabbix-server zabbix-agent httpd rh-php72-php-fpm 也可以直接kill -9 ...
- java 输入输出IO流:FileOutputStream FileInputStream
什么是IO: 生活中,你肯定经历过这样的场景.当你编辑一个文本文件,忘记了 ctrl+s ,可能文件就白白编辑了.当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里.那么数据都是在哪些设备上 ...
- bootstrap栅格例子
<div class="container-fluid "> <div class="row"> <div class=" ...