.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 ...
随机推荐
- 【编程思想】【设计模式】【结构模式Structural】front_controller
Python版 https://github.com/faif/python-patterns/blob/master/structural/front_controller.py #!/usr/bi ...
- 使用递归方法,遍历输出以.java结尾的文件
package cn.itcast.demo01;import java.io.File;/** * @author newcityman * @date 2019/7/27 - 19:17 * 题目 ...
- ssm中的注解
1.@Controller 2.@RequestMapping 3.@RequestParam public String getUser(HttpSession session,@RequestPa ...
- 搭建直接通过CPU执行汇编语言的环境
搭建直接通过CPU执行汇编语言环境 我们通过编译写好的汇编语言代码可以生成.bin的机器语言二进制代码.但是这个.bin程序我们该如何运行呢? 这里其实有两个办法: 1: 将其作为一个Windows/ ...
- setsockopt()用法及参数详解
setsockopt()用法(参数详细说明) int setsockopt(SOCKET s,int level,int optname,const char* optval,int optlen); ...
- java多线程8:阻塞队列与Fork/Join框架
队列(Queue),是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的. BlockingQueue 而阻塞队列BlockingQueue除了继承 ...
- TensorFlow.NET机器学习入门【0】前言与目录
曾经学习过一段时间ML.NET的知识,ML.NET是微软提供的一套机器学习框架,相对于其他的一些机器学习框架,ML.NET侧重于消费现有的网络模型,不太好自定义自己的网络模型,底层实现也做了高度封装. ...
- CF716A Crazy Computer 题解
Content 有一个电脑,如果过了 \(c\) 秒之后还没有任何打字符的操作,就把屏幕上面所有的字符清空.现在,给定 \(n\) 次打字符的时间 \(t_1,t_2,...,t_n\),求最后屏幕剩 ...
- sqlalchemy-orm学生签到 成绩记录查询系统
#!/usr/bin/env python # Author:zhangmingda '''''' from sqlalchemy import create_engine,ForeignKey,DA ...
- TCP超时、ping不丢包排查
现象就是:1. 每隔一段时间,问题服务器的公网地址不可访问,目前只开放了8080和22,这两个端口不可访问的时间是一致的,不可访问时间约在2分钟以内2. 已经建立的连接在不可访问期间不受影响,开的几个 ...