补充一下ServiceProvider的内容

  可能上一篇文章DOTNET CORE源码分析之IServiceProvider、ServiceProvider、IServiceProviderEngine、ServiceProviderEngine和ServiceProviderEngineScope 中还没有关联上ServiceProvider和ServiceCollection就直接通过GetService获取了值,这样不科学啊。其实是有关联的,请看一下上篇文章同样存在的一个代码段:

internal ServiceProvider(
IEnumerable<ServiceDescriptor> serviceDescriptors,
ServiceProviderOptions options)
{
IServiceProviderEngineCallback callback = (IServiceProviderEngineCallback) null;
if (options.ValidateScopes)
{
callback = (IServiceProviderEngineCallback) this;
this._callSiteValidator = new CallSiteValidator();
}
switch (options.Mode)
{
case ServiceProviderMode.Dynamic:
this._engine = (IServiceProviderEngine) new DynamicServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Runtime:
this._engine = (IServiceProviderEngine) new RuntimeServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Expressions:
this._engine = (IServiceProviderEngine) new ExpressionsServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.ILEmit:
this._engine = (IServiceProviderEngine) new ILEmitServiceProviderEngine(serviceDescriptors, callback);
break;
default:
throw new NotSupportedException("Mode");
}
}

  是的在这个构造函数中第一个参数:IEnumerable<ServiceDescriptor> serviceDescriptors,这个就是ServiceCollection的对应参数,这样,保存了用户添加的注入信息就和ServiceProviderEngine关联上了,然后ServiceProviderEngine可以为调用方提供数据,换句话说,ServiceProvider不是直接提供数据响应,而是借用ServiceProviderEngine的子类来提供,并且提供了ServiceProviderMode中提供的几种方式。

  我们再看看ServiceProviderMode的构造函数,如下:

protected ServiceProviderEngine(
IEnumerable<ServiceDescriptor> serviceDescriptors,
IServiceProviderEngineCallback callback)
{
this._createServiceAccessor = new Func<Type, Func<ServiceProviderEngineScope, object>>(this.CreateServiceAccessor);
this._callback = callback;
this.Root = new ServiceProviderEngineScope(this);
this.RuntimeResolver = new CallSiteRuntimeResolver();
this.CallSiteFactory = new CallSiteFactory(serviceDescriptors);
this.CallSiteFactory.Add(typeof (IServiceProvider), (IServiceCallSite) new ServiceProviderCallSite());
this.CallSiteFactory.Add(typeof (IServiceScopeFactory), (IServiceCallSite) new ServiceScopeFactoryCallSite());
this.RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
}

  这个过程做了很多初始化,我们把关注点集中在这一句:this.CallSiteFactory = new CallSiteFactory(serviceDescriptors),这句把ServiceCollection传递给了CallSiteFactory。CallSiteFactory是创建ServiceCallSite的工厂,具体作用下如下代码中:

private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(
Type serviceType)
{
IServiceCallSite callSite = this.CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain());
if (callSite == null)
return (Func<ServiceProviderEngineScope, object>) (_ => (object) null);
this._callback?.OnCreate(callSite);
return this.RealizeService(callSite);
}

  这里的IServiceCallSite callSite = this.CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain()) 函数CreateCallSite实现如下:

internal IServiceCallSite CreateCallSite(
Type serviceType,
CallSiteChain callSiteChain)
{
lock (this._callSiteCache)
{
IServiceCallSite serviceCallSite1;
if (this._callSiteCache.TryGetValue(serviceType, out serviceCallSite1))
return serviceCallSite1;
IServiceCallSite serviceCallSite2;
try
{
callSiteChain.CheckCircularDependency(serviceType);
serviceCallSite2 = this.TryCreateExact(serviceType, callSiteChain) ?? this.TryCreateOpenGeneric(serviceType, callSiteChain) ?? this.TryCreateEnumerable(serviceType, callSiteChain);
}
finally
{
callSiteChain.Remove(serviceType);
}
this._callSiteCache[serviceType] = serviceCallSite2;
return serviceCallSite2;
}
}

  其中this.TryCreateExact(serviceType, callSiteChain) ?? this.TryCreateOpenGeneric(serviceType, callSiteChain) ?? this.TryCreateEnumerable(serviceType, callSiteChain) 这个返回值是带有结果的ServiceCallSite,然后通过这个ServiceCallSite获取最终结果。

  接着介绍昨天没完成的内容

  昨天介绍到这个获取服务的函数,如下:

protected override Func<ServiceProviderEngineScope, object> RealizeService(
IServiceCallSite callSite)
{
int callCount = 0;
return (Func<ServiceProviderEngineScope, object>) (scope =>
{
if (Interlocked.Increment(ref callCount) == 2)
Task.Run<Func<ServiceProviderEngineScope, object>>((Func<Func<ServiceProviderEngineScope, object>>) (() => base.RealizeService(callSite)));
return this.RuntimeResolver.Resolve(callSite, scope);
});
}

  关注点停留在this.RuntimeResolver.Resolve(callSite, scope),这个函数在调用过程的时候带有两个参数callSite和scope,callSite就是刚刚介绍的ServiceCallSite,Scope是ServiceProviderEngineScope。RuntimeResolver是CallSiteRuntimeResolver的实例,Resolve方法如下:

public object Resolve(IServiceCallSite callSite, ServiceProviderEngineScope scope)
{
return this.VisitCallSite(callSite, scope);
}

  其中VisitCallSite就是:

protected virtual TResult VisitCallSite(IServiceCallSite callSite, TArgument argument)
{
switch (callSite.Kind)
{
case CallSiteKind.Factory:
return this.VisitFactory((FactoryCallSite) callSite, argument);
case CallSiteKind.Constructor:
return this.VisitConstructor((ConstructorCallSite) callSite, argument);
case CallSiteKind.Constant:
return this.VisitConstant((ConstantCallSite) callSite, argument);
case CallSiteKind.IEnumerable:
return this.VisitIEnumerable((IEnumerableCallSite) callSite, argument);
case CallSiteKind.ServiceProvider:
return this.VisitServiceProvider((ServiceProviderCallSite) callSite, argument);
case CallSiteKind.Scope:
return this.VisitScoped((ScopedCallSite) callSite, argument);
case CallSiteKind.Transient:
return this.VisitTransient((TransientCallSite) callSite, argument);
case CallSiteKind.CreateInstance:
return this.VisitCreateInstance((CreateInstanceCallSite) callSite, argument);
case CallSiteKind.ServiceScopeFactory:
return this.VisitServiceScopeFactory((ServiceScopeFactoryCallSite) callSite, argument);
case CallSiteKind.Singleton:
return this.VisitSingleton((SingletonCallSite) callSite, argument);
default:
throw new NotSupportedException(string.Format("Call site type {0} is not supported", (object) callSite.GetType()));
}
}

  然后:

protected override object VisitConstant(
ConstantCallSite constantCallSite,
ServiceProviderEngineScope scope)
{
return constantCallSite.DefaultValue;
}

  这个constantCallSite.Defaultvalue就是需要的返回结果了。

  上述的源码过程解析如下代码:

IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(typeof(string), "lizizhang");
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
string name = (string)serviceProvider.GetService(typeof(string));

  如果错误之处,请及时指正!

DOTNET CORE源码分析之IOC容器结果获取内容补充的更多相关文章

  1. Spring源码分析专题 —— IOC容器启动过程(上篇)

    声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...

  2. 【spring源码分析】IOC容器初始化(总结)

    前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正 ...

  3. 【spring源码分析】IOC容器初始化(二)

    前言:在[spring源码分析]IOC容器初始化(一)文末中已经提出loadBeanDefinitions(DefaultListableBeanFactory)的重要性,本文将以此为切入点继续分析. ...

  4. 【spring源码分析】IOC容器初始化(三)

    前言:在[spring源码分析]IOC容器初始化(二)中已经得到了XML配置文件的Document实例,下面分析bean的注册过程. XmlBeanDefinitionReader#registerB ...

  5. 【spring源码分析】IOC容器初始化(四)

    前言:在[spring源码分析]IOC容器初始化(三)中已经分析了BeanDefinition注册之前的一些准备工作,下面将进入BeanDefinition注册的核心流程. //DefaultBean ...

  6. 【spring源码分析】IOC容器初始化(七)

    前言:在[spring源码分析]IOC容器初始化(六)中分析了从单例缓存中加载bean对象,由于篇幅原因其核心函数 FactoryBeanRegistrySupport#getObjectFromFa ...

  7. 【spring源码分析】IOC容器初始化(十)

    前言:前文[spring源码分析]IOC容器初始化(九)中分析了AbstractAutowireCapableBeanFactory#createBeanInstance方法中通过工厂方法创建bean ...

  8. 【spring源码分析】IOC容器初始化——查漏补缺(一)

    前言:在[spring源码分析]IOC容器初始化(十一)中提到了初始化bean的三个步骤: 激活Aware方法. 后置处理器应用(before/after). 激活自定义的init方法. 这里我们就来 ...

  9. 【spring源码分析】IOC容器初始化——查漏补缺(五)

    前言:我们知道在Spring中经常使用配置文件的形式对进行属性的赋值,那配置文件的值是怎么赋值到属性上的呢,本文将对其进行分析. 首先了解一个类:PropertySourcesPlaceholderC ...

随机推荐

  1. Dcoker跨主机容器通信之overlay

    同样是两台服务器: 准备工作: 设置容器的主机名 consul:kv类型的存储数据库(key:value) docker01.02上: vim /etc/docker/daemon.json { &q ...

  2. [USACO5.1] Musical Themes

    后缀数组求最长重复且不重叠子串. poj 1743 传送门 洛谷 P2743 传送门 1.子串可以“变调”(即1 3 6和3 5 8视作相同).解决办法:求字符串相邻元素的差形成新串.用新字符串求解最 ...

  3. 吴裕雄--天生自然python编程:turtle模块绘图(1)

    Turtle库是Python语言中一个很流行的绘制图像的函数库,想象一个小乌龟,在一个横轴为x.纵轴为y的坐标系原点,(0,0)位置开始,它根据一组函数指令的控制,在这个平面坐标系中移动,从而在它爬行 ...

  4. AWS CloudFront / 亚马逊CDN使用教程

    步骤: 1. 打开CloudFront服务之后,首先需要选择分发类型.分发类型分为一般的静态文件分发和流媒体分发,即Web和RTMP,我的站点即选择Web类型. 2. CDN回源设定. a. 首先要填 ...

  5. 遗弃.Forsaken.2015.BluRay.720p.x264.DTS-beAst

    ◎译 名 遗弃/落日孤影(台)/赎罪◎片 名 Forsaken◎年 代 2015◎产 地 加拿大/法国/美国◎类 别 剧情/西部◎语 言 英语◎上映日期 2015-09-16(多伦多电影节)/2016 ...

  6. Linux内核初探 之 进程(三) —— 进程调度算法

    一.基本概念 抢占 Linux提供抢占式多任务,基于时间片和优先级对进程进行强制挂起 非抢占的系统需要进程自己让步(yielding) 进程类型 IO消耗型 经常处于可运行态,等待IO操作过程会阻塞 ...

  7. Linux系统发行版本及其区别

    1 Linux系统组成 Linux操作系统=Linux内核+GNU软件及系统软件+必要的应用程序.下表为Linux系统各组成部分的贡献人员: Linux内核 GNU组件(gcc.bash) 其他必要应 ...

  8. 【ThinkPHP6:从TP3升级到放弃】1. 前言及准备工作

    春节期间因为疫情的关系出不去门,所以就研究了一下ThinkPHP的最新版本6.0.2, 自己写了一个博客程序. 现在, 打算写一个ThinkPHP6的专题, 用来把自己在写博客的过程中入过的坑和获得的 ...

  9. Java反射,泛型在Json中的运用

    最近项目中遇到了Json数据自动获取的功能,不然令人想起java的反射,已经很长时间没复习java了正好一块连java的这一块内容一起过一遍.java中的反射无疑就相当于java开发者的春天,在众多的 ...

  10. idea通过maven打jar包不成功或无法加载主类或打成功也找不到jar包

    这个问题纠结了我一天,在网上也搜了一些方法,现在把我自己的处理过程记录一下,以方便遇到此类问题的小伙伴参考: 第一步:查看idea的jdk版本与Windows安装的jdk是不是同一个版本,如下图 第二 ...