Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor
CallSiteRuntimeResolver
CallSiteRuntimeResolver
是实现了CallSiteVisitor之一。
提供的方法主要分三个部分
自有成员方法
- Resolve提供服务
- VisitCache
- 私有构造函数
重写父类方法
VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
调用父类VisitCallSiteMain ,并把创建出来的服务添加到context.Scope.CaptureDisposablereturn context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context));
object VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
- 先找对应callSite.Value是否有值如果有直接返回
- 如果没有直接调用 VisitCallSiteMain创建服务并把对象rootServiceProviderEngine内。
- 创建的服务放入callSite.Value。
if (callSite.Value is object value)
{
return value;
} var lockType = RuntimeResolverLock.Root;
ServiceProviderEngineScope serviceProviderEngine = context.Scope.RootProvider.Root;
if (callSite.Value is object resolved)
{
return resolved;
}
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
serviceProviderEngine.CaptureDisposable(resolved);
callSite.Value = resolved;
return resolved;
VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
- 先去serviceProviderEngine.resolvedServices拿,有的话直接返回如果没拿到执行步骤2去创建。serviceProviderEngine.resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved)
- VisitCallSiteMain创建对象
- 把创建后的对象加入对应Scope的 disposable列表
- 把创建后的对象加入对应Scope的 resolvedServices列表
if (resolvedServices.TryGetValue(callSite.Cache.Key, out object resolved))
{
return resolved;
}
resolved = VisitCallSiteMain(callSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
serviceProviderEngine.CaptureDisposable(resolved);
resolvedServices.Add(callSite.Cache.Key, resolved);
return resolved;
实现父类抽象方法
- VisitConstructor
- 给构造方法提供参数(如果有参数递归调用VisitCallSite创建参数对象)
- 直接调用ServiceCallSite的ConstructorInfo反射创建对象。
object[] parameterValues;
if (constructorCallSite.ParameterCallSites.Length == 0)
{
parameterValues = Array.Empty<object>();
}
else
{
parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
for (int index = 0; index < parameterValues.Length; index++)
{
parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
}
} return constructorCallSite.ConstructorInfo.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameterValues, culture: null);
- override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
直接返回CallSite对象的DefaultValue
return constantCallSite.DefaultValue;
- VisitServiceProvider
return context.Scope;
- override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
根据ServiceCallSites直接循环调用VisitCallSite创建实例,然后根据实例创建集合返回var array = Array.CreateInstance(
enumerableCallSite.ItemType,
enumerableCallSite.ServiceCallSites.Length);
for (int index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
{
object value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
array.SetValue(value, index);
}
return array;
- VisitFactory
return factoryCallSite.Factory(context.Scope);
- VisitConstructor
体力活都给CallSiteFactory了
CallSiteVisitor
- 方法
VisitCallSite(ServiceCallSite callSite, TArgument argument)
- 保证Stack安全
- 根据callSite的Cache.Location去调用不同策略的Cache方法。
switch (callSite.Cache.Location)
{
case CallSiteResultCacheLocation.Root:
return VisitRootCache(callSite, argument);
case CallSiteResultCacheLocation.Scope:
return VisitScopeCache(callSite, argument);
case CallSiteResultCacheLocation.Dispose:
return VisitDisposeCache(callSite, argument);
case CallSiteResultCacheLocation.None:
return VisitNoCache(callSite, argument);
default:
throw new ArgumentOutOfRangeException();
}
VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
- 根据不同CallSiteKind去调用不同策略的创建服务方法。
switch (callSite.Kind)
{
case CallSiteKind.Factory:
return VisitFactory((FactoryCallSite)callSite, argument);
case CallSiteKind.IEnumerable:
return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
case CallSiteKind.Constructor:
return VisitConstructor((ConstructorCallSite)callSite, argument);
case CallSiteKind.Constant:
return VisitConstant((ConstantCallSite)callSite, argument);
case CallSiteKind.ServiceProvider:
return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
default:
throw new NotSupportedException(SR.Format(SR.CallSiteTypeNotSupported, callSite.GetType()));
}
- 根据不同CallSiteKind去调用不同策略的创建服务方法。
- 虚方法
- TResult VisitNoCache(ServiceCallSite callSite, TArgument argument) => VisitCallSiteMain(callSite, argument);
- TResult VisitDisposeCache(ServiceCallSite callSite, TArgument argument) -> isitCallSiteMain(callSite, argument);
- TResult VisitRootCache(ServiceCallSite callSite, TArgument argument) -> VisitCallSiteMain(callSite, argument);
- TResult VisitScopeCache(ServiceCallSite callSite, TArgument argument) => VisitCallSiteMain(callSite, argument);
根据生命周期策略由子类实现对应存储机制。
- 抽象方法
- TResult VisitConstructor(ConstructorCallSite constructorCallSite, TArgument argument);
- TResult VisitConstant(ConstantCallSite constantCallSite, TArgument argument);
- TResult VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, TArgument argument);
- TResult VisitIEnumerable(IEnumerableCallSite enumerableCallSite, TArgument argument);
- TResult VisitFactory(FactoryCallSite factoryCallSite, TArgument argument);
根据服务注册时的创建机制策略由子类实现对应的创建对象机制。
CallSiteVisitor负责这活怎么干!。CallSiteRuntimeResolver负责干活
- 调用 VisitCallSite在内部区分出scope并调用具体实现方法缓存方法 (CallSiteResultCacheLocation),
-> VisitCache方法
-> 但是在缓存前得先得到被缓存的对象,这时通过调用(VisitCallSiteMain)创建对象
-> VisitCallSiteMain根据提供的callsite类型去调用实现的抽象方法创建对应对象
-> 根据cache对应的方法缓存步骤1.1的结果。 - return cahce的结果。
整体的获取对象流程大约如下
CallSiteRuntimeResolver.Resolve -> CallSiteVisitor->VisitCallSite callSite.Cache.Location VisitRootCache/VisitScopeCache/ VisitDisposeCache/ VisitNoCache -> CallSiteRuntimeResolver.VisitCache/ VisitRootCache -> VisitRootCache -> CallSiteVisitor.VisitCallSiteMain 根据callSite.Kind CallSiteRuntimeResolver.VisitFactory(abstract TResult VisitFactory)递归调用 VisitCallSite
Net6 DI源码分析Part3 CallSiteRuntimeResolver,CallSiteVisitor的更多相关文章
- Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的?
Net6 DI源码分析Part5 在Kestrel内Di Scope生命周期是如何根据请求走的? 在asp.net core中的DI生命周期有一个Scoped是根据请求走的,也就是说在处理一次请求时, ...
- Net6 DI源码分析Part4 CallSiteFactory ServiceCallSite
Net6 CallSiteFactory ServiceCallSite, CallSiteChain abstract class ServiceCallSite ServiceCallSite是个 ...
- Net6 DI源码分析Part2 Engine,ServiceProvider
ServiceProvider ServiceProvider是对IServiceProvider实现,它有一个internal的访问修饰符描述的构造,并需要两个参数IServiceCollectio ...
- Net6 DI源码分析Part1 ServiceCollection、ServiceDescriptor、ServiceLifetime、IServiceProvider
ServiceCollection.ServiceDescriptor.ServiceLifetime.IServiceProvider Microsoft.Extensions.Dependency ...
- Net6Configuration & Options 源码分析 Part3 IOptionsMonitor 是如何接收到配置文件变更并同步数据源的
配置源的同步 IOptionsMonitor 使用 //以下demo演示使用IOptionsMonitor重新加载配置并当重新加载配置是执行回调函数 var configuration = new C ...
- 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析
目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...
- Net6 Configuration & Options 源码分析 Part2 Options
Net6 Configuration & Options 源码分析 Part2 Options 第二部分主要记录Options 模型 OptionsConfigurationServiceCo ...
- 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器
1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...
- Net6 Configuration & Options 源码分析 Part1
Net6 Configuration & Options 源码分析 Part1 在Net6中配置系统一共由两个部分组成Options 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...
随机推荐
- Linux 安装并启用 PHP-FPM
首先,在编译时带上 --enable-fpm 参数: [root@localhost local]# yum -y install libxml2 libxml2-devel gd gd-devel ...
- laravel源码分析-队列Queue
laravel 源码分析具体注释见 https://github.com/FX-Max/source-analysis-laravel 前言 队列 (Queue) 是 laravel 中比较常用的一个 ...
- 怎样安装python的 模块、 包、 库方法总结
pip install 模块,这种输入命令回车后 1.pip install six 回车,安装成功后显示sucess 2.pip install lxml 回车,显示正在下载中的,可将这个下载地址复 ...
- 初识python 之 自动拆分转换文本内容
上一篇升级版,转换文件内容. #!/user/bin env python # author:Simple-Sir # time:2021/7/9 23:32 def txt_2_list(filen ...
- spring boot 解决 跨域 的两种方法 -- 前后端分离
1.前言 以前做项目 ,基本上是使用 MVC 模式 ,使得视图与模型绑定 ,前后端地址与端口都一样 , 但是现在有些需求 ,需要暴露给外网访问 ,那么这就出现了个跨域问题 ,与同源原则冲突, 造成访问 ...
- Python之路 - Day4 - Python基础4 (新版)
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1.列表生成式,迭代器&生成器 列表生成式 孩子,我现在有个需 ...
- Hive分析统计离线日志信息
关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新)云盘目录说明:tools目录是安装包res 目录是每一个课件对应的代码和资源等doc 目录是一 ...
- Java在linux环境下和windows环境下日期字符串显示不同
图片如果损坏,点击链接: https://www.toutiao.com/i6511565147322974724/ 出现的现象: 在Java中我想要将当前的时间格式化为需要的字符串,然后存放到数据库 ...
- vue3.0+vite+ts项目搭建-分环境打包(四)
分环境打包配置 新建.env.dev(或者.env) VITE_NODE_ENV = 'dev' VITE_HOST = 'http://local.host.com' 执行yarn dev ,控制台 ...
- Java中运算符及其优先级、自动类型提升、类型转化
自动类型提升的规则 两个操作数中有一个为double型的数据,计算结果提升为double. 两个操作数中无double型,有一个float,计算结果自动提升为float. ...