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 模型与配置系统.它们是两个完全独立的系统. 第一部分主要记 ...
随机推荐
- Docker下安装Elasticsearch、ik分词器、kibana
1:使用docker拉取Elasticsearch镜像 docker pull elasticsearch:7.12.0(不加版本号默认是最新版本) 2:查看是否成功下载镜像 docker image ...
- Jenkins_centos7安装jenkins(1)
Jenkins自动化部署的流程 一.下载安装 下载安装JDK wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/j ...
- 深入研究 synchronized 同步锁 作用于 静态方法 和 非静态方法 的 区别
1.前言 众所周知, synchronized 是同步锁 ,虽然在底层又细分了无锁.偏向锁.轻量级锁.自旋锁 以及重量级锁 机制, 这些底层锁知道一下原理即可 ,[想要 了解 这篇 博文 有 解释 : ...
- Centos7 文件权限理解(持续更新)
后期排版,边学边记边敲 用户详情分析 管理员用户 root 0 虚拟用户 nobody 1-999 普通用户 test001 1000+ 输入ll命令查看当前目录文件详情 根据这张图片可知,目录 ...
- react中create-react-app配置antd按需加载(方法二)
1.yarn add babel-plugin-import 2.在根目录下的package.json下的bable中添加相应代码 "babel": { "presets ...
- Hackurllib
是的大部分的http请求库都不够hacking 不过有w8ay师傅的hack-requests 但是我想造一个属于自己的轮子它将会足够简单足够hacking 用这个名字是因为我选择了urllib做为最 ...
- 【Java常用类】StringBuffer、StringBuilder
Stringbuffer.StringBuilder String.StringBuffer.StringBuilder三者的异同? String:不可变的字符序列:底层使用char[]存储 Stri ...
- day 19 C语言顺序结构基础2
(1).算术运算符和圆括号有不同的运算优先级,对于表达式:a+b+c*(d+e),关于执行步骤,以下说法正确的是[A] (A).先执行a+b的r1,再执行(d+e)的r2,再执行c*r2的r3,最后执 ...
- system (color XX )函数详解:调整控制台颜色的命令
1.指定控制台输出的颜色属性 2.颜色属性由两个十六进制数字指定 -- 第一个为背景,第二个则为前景.每个数字可以为以下任何值之一: 例如: "COLOR fc" 在亮白色上产生亮 ...
- js监听url的hash变化和获取hash值
当浏览器浏览器的url进行变化时,浏览器默认是会去服务器将相应的资源给请求下来的,在不阻止默认行为的前提下,使用给url加锚点的方式(hash模式),让浏览器不跳转. window.addEventL ...