在上一节的学习中,我们已经知道了通过 IServiceCollection 拓展方法创建 IServiceProvider 默认的是一个类型为 ServiceProvider 对象,并且实际提供创建对象功能的是它的内部为类型为 IServiceProviderEngine 对象,实际上关于 IServiceProvider 的架构比我们想象的还要复杂的多,一个是根容器的概念,另一个就是使用编译时引擎(CompliedServiceProviderEngine)动态构建表达式树,提高了创建实例的效率。

容器、引擎和根容器

在这张类图中,有三个核心接口,IServiceProvider 表示容器,具备提供对象功能,IServiceScope 代表一个具有范围的节点容器,而 IServiceProviderEngine 是提供对象核心接口,具有一个根容器,每次创建对象的时候都会带上具有范围的节点容器。关于容器和引擎这两个概念如何判断呢?凡是实现了 IServiceProvider 的都可以称为容器,同样的,凡是实现了 IServiceProviderEngine 的都可以称为引擎,引擎仍然是一个容器,实际上,上图中所有的类型都是一个容器,因为他们都直接或者间接实现了 IServiceProvider 接口,然而最终负责创建服务实例的必然是一个引擎!

public interface IServiceProvider
{
object GetService(Type serviceType);
}
public interface IServiceScope : IDisposable
{
IServiceProvider ServiceProvider { get; }
}
internal interface IServiceProviderEngine : IDisposable, IServiceProvider
{
IServiceScope RootScope { get; }
}

ServiceProviderEngineScope

IServiceScope 的默认实现是 ServiceProviderEngineScope,ResolvedServices 存储已经实例化过的生命周期为 Scoped 的对象,_disposables 存储通过该根创建的所有实例类型(如果该类型实现了 IDisposable 接口),在调用 Dispose 方法时会释放 _disposables 中的对象,同时清空 ResolvedServices 中的实例。

internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
{
private List<IDisposable> _disposables = new List<IDisposable>();
public ServiceProviderEngineScope(ServiceProviderEngine engine)
{
Engine = engine;
} internal Dictionary<object, object> ResolvedServices { get; } = new Dictionary<object, object>();
public ServiceProviderEngine Engine { get; }
public object GetService(Type serviceType)
{
return Engine.GetService(serviceType, this);
}
public IServiceProvider ServiceProvider => this;
//省略了一些代码
}

ServiceProviderEngineScope 总在引擎被创建的时候初始化,并且在 GetService 方法中,传递的根容器正是这个 Root,所以根容器一般情况不会更改,然而我们可以 CreateScope 方法(来自 IServiceScopeFactory 接口)来创建一个新的根容器(实际上是一个新的节点),实际上到这里可能还是很难理解这个作用域是如何形成的,没关系,后面还会介绍!

internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
{
protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
Root = new ServiceProviderEngineScope(this);
}
   public object GetService(Type serviceType) => GetService(serviceType, Root);
public ServiceProviderEngineScope Root { get; }
public IServiceScope CreateScope()
{
return new ServiceProviderEngineScope(this);
}
}

默认的容器 ServiceProvider

ServiceProviderOptions

public static class ServiceCollectionContainerBuilderExtensions
{
public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
{
return BuildServiceProvider(services, ServiceProviderOptions.Default);
}
public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
{
return new ServiceProvider(services, options);
}
}
public class ServiceProviderOptions
{
internal static readonly ServiceProviderOptions Default = new ServiceProviderOptions();
public bool ValidateScopes { get; set; }
internal ServiceProviderMode Mode { get; set; } = ServiceProviderMode.Dynamic;
}

我们知道在 IServiceCollection 的拓展方法 BuildServiceProvider 最终返回的是一个 ServiceProvider,由于默认的 ServiceProviderMode 是 Dynamic,所以默认情况下,提供服务的是一个 DynamicServiceProviderEngine 对象,然而它与 CompiledServiceProviderEngine 唯一的区别就是抽象方法 RealizeService 的实现,前者提供真正的创建对象的方法,而后者将前者提供的创建对象的方法翻译成表达式树。

ServiceProvider

public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
{
private readonly IServiceProviderEngine _engine; private readonly CallSiteValidator _callSiteValidator; internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
IServiceProviderEngineCallback callback = null;
if (options.ValidateScopes)
{
callback = this;
_callSiteValidator = new CallSiteValidator();
}
switch (options.Mode)
{
case ServiceProviderMode.Dynamic:
_engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Runtime:
_engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Compiled:
_engine = new CompiledServiceProviderEngine(serviceDescriptors, callback);
break;
default:
throw new ArgumentOutOfRangeException(nameof(options.Mode));
}
}
}

因为 ServiceProviderOptions.Default 提供的参数中 ValidateScoped 默认值是 False,所以这里不打算介绍 IServiceProviderEngineCallback 以及 CallSiteValidator 这两个类型(和服务实例对象的创建有关,后续介绍)。根据参数 option 的 Mode 为 Dynamic,创建了一个类型为 DynamicServiceProviderEngine 的引擎,实际上该引擎是如何创建对象是后续要讲的,这里我们只关注它的创建过程,所以我们又来到了 ServiceProviderEngine 的构造函数。

ServiceProviderEngine

internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory
{
protected abstract Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite); internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; } =
new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>(); private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor; protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
_createServiceAccessor = CreateServiceAccessor;
_callback = callback; Root = new ServiceProviderEngineScope(this);
RuntimeResolver = new CallSiteRuntimeResolver();
ExpressionBuilder = new CallSiteExpressionBuilder(RuntimeResolver, this, Root);
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
} private readonly IServiceProviderEngineCallback _callback;
internal CallSiteFactory CallSiteFactory { get; }
protected CallSiteRuntimeResolver RuntimeResolver { get; }
protected CallSiteExpressionBuilder ExpressionBuilder { get; }
public ServiceProviderEngineScope Root { get; }
public IServiceScope RootScope => Root; private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
{
var callSite = CallSiteFactory.CreateCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
_callback?.OnCreate(callSite);
return RealizeService(callSite);
} return _ => null;
}

这是一个抽象类,还记得我们前面提起过得 IServiceCallSite 吗?它是创建服务实例的依据,虽然还没有得到证实,但是我们要坚信!然后我们看抽象方法 RealizeService,它是一个方法,提供一个委托,该委托接受一个根容器,然后返回一个实例对象,可能有点绕,简而言之这个抽象方法提供一个方法,该方法可以实现服务实例的创建!

internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
public DynamicServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
{
} protected override Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite)
{
var callCount = ;
return scope =>
{
if (Interlocked.Increment(ref callCount) == )
{
Task.Run(() => base.RealizeService(callSite));
}
return RuntimeResolver.Resolve(callSite, scope);
};
}
}

如果我们对该抽象方法返回的委托理解了,那也会很容易理解字典 RealizedServices,和那个委托一样,这个字典存储的是每个服务类型的创建实例的方法,同样的,委托 _createServiceAccessor 也很好理解。关于 CallSiteRuntimeResolver,这里只需要知道在 DynamicServiceProviderEngine 实现的 RealizeService 方法中,最后返回的委托是根据它来解析 IServiceCallSite 来创建实例的!CallSiteExpressionBuilder 这个类型是在 CompiledServiceProviderEngine中实现将创建实例的过程构建成表达式树的,详细过程后续讲,但是这里需要知道对于同一个服务,创建其实例的过程应当总是一致的,而这个过程就保存在 RealizedServices 中,而实际创建实例的过程在 DynamicServiceProviderEngine 中,我们在 DynamicServiceProviderEngine 的 RealizeService 方法中发现,如果是第二次创建该实例,则会调用父类 CompiledServiceProviderEngine 的 RealizeService 方法,并且它是以异步方式执行的,尽管如此,最后创建实例的方法仍然是 DynamicServiceProviderEngine 提供的委托,然而 CompiledServiceProviderEngine 的 RealizeService 方法做了些什么呢?

internal class CompiledServiceProviderEngine : ServiceProviderEngine
{
public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
{
} protected override Func<ServiceProviderEngineScope, object> RealizeService(IServiceCallSite callSite)
{
var realizedService = ExpressionBuilder.Build(callSite);
RealizedServices[callSite.ServiceType] = realizedService;
return realizedService;
}
}

实际上这里返回的 realizedService 永远都不会得到调用(由于它返回的是一个委托,这里的不会调用不是指委托不会调用,这里的永远不会调用是指不会简单的通过调用该方法获取它的返回值),但是这个委托却永远的替换了 RealizedServices 中的某个委托(采用了表达式树重新构建了创建实例的委托),而新的以表达式树构建的委托是如何地调调用的呢?

internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
{
var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor);
_callback?.OnResolve(serviceType, serviceProviderEngineScope);
return realizedService.Invoke(serviceProviderEngineScope);
}

我们看到在 ServiceProviderEngine 的 GetService 方法中,只要 RealizedServices 中已经存在该服务的创建实例的委托就不会通过 CreateServiceAccessor 再去调用抽象方法获取委托,也就是说被 CompiledServiceProviderEngine 执行它自己的 RealizeService 方法后,以后创建该服务的实例对象总是通过表达式树创建的。

小结

在这一节中,我们学习了容器创建过程中的一些核心类型,然而最核心的依然在 ServiceProviderEngine 这个抽象类中,尽管提供了抽象方法 RealizeService 允许子类提供创建实例的委托,但是创建实例的具体逻辑依然有它自己的 CallSiteRuntimeResolver 提供,再加上创建实例的方法始终都是通过委托提供的,所以使得 DynamicServiceProviderEngine 和 CompileServiceProviderEngine 这两个类非常的简洁,但是依然对 DynamicServiceProviderEngine 是如何使用 CallSiteRuntimeResolver 创建实例的,CompileServiceProviderEngine 又是如何构建表达式树的,作用域又是如何形成的,因为这些都和 IServiceCallSite 有离不开的关系。

解析 .Net Core 注入 (2) 创建容器的更多相关文章

  1. 解析 .Net Core 注入 (1) 注册服务

    在学习 Asp.Net Core 的过程中,注入可以说是无处不在,对于 .Net Core 来说,它是独立的一个程序集,没有复杂的依赖项和配置文件,所以对于学习 Asp.Net Core 源码的朋友来 ...

  2. 解析 .Net Core 注入——注册服务

    在学习 Asp.Net Core 的过程中,注入可以说是无处不在,对于 .Net Core 来说,它是独立的一个程序集,没有复杂的依赖项和配置文件,所以对于学习 Asp.Net Core 源码的朋友来 ...

  3. 解析 .Net Core 注入 (3) 创建对象

    回顾 通过前两节的学习,我们知道 IServiceCollection 以元数据(ServiceDescriptor)的形式存放着用户注册的服务,它的 IServiceCollection 的拓展方法 ...

  4. .Net Core 注入学习——注册服务

    解析 .Net Core 注入——注册服务发表于:2017-10-23 10:47 作者:行走即歌 来源:51Testing软件测试网采编字体:大 中 小 | 上一篇 | 下一篇 |我要投稿 | 推荐 ...

  5. .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]

    原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...

  6. Docker 为 ASP.NET Core WebApi 应用程序生成 Docker 映像,创建容器并运行

    1.使用VS2017新建ASP.NET Core WebApi项目 选择API启用Docker支持 2.为 ASP.NET Core WebApi 应用程序生成 Docker 映像,并创建容器运行 生 ...

  7. 翻译-在10行代码之内创建容器化的.net core应用

    本文翻译自Hans Kilian的文章 Creating a containerized .NET core application in less than 10 lines of code htt ...

  8. 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表

    创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表 创建数据模型类(POCO类) 在Models文件夹下添 ...

  9. .net core 注入机制与Autofac

    本来是要先出注入机制再出 管道 的,哈哈哈……就是不按计划来…… 这里扯扯题外话:为什么要注入(DI,dependency-injection),而不用 new 对象? 可能我们都很清楚,new 对象 ...

随机推荐

  1. 201521123070 《JAVA程序设计》第4周学习总结

    1. 本章学习总结 1.1 尝试使用思维导图总结有关继承的知识点. http://naotu.baidu.com/file/4de6f42e4f4f6cce0531dd9997b04e60?token ...

  2. MySql数据库第一天

    LAMP  linux apache mysql php的关系服务器软件 “服务器” 数据库 操作 mysql常用数据类型:int varchar float double bit datetime. ...

  3. [js高手之路]Node.js+jade抓取博客所有文章生成静态html文件

    这个周末,恶补了一下jade模板引擎,就为生成静态html文件,这篇文章需要知道jade以及看过我的上篇文章,我先给出他们的参考链接: [js高手之路]Node.js模板引擎教程-jade速学与实战1 ...

  4. ACM学习之路___HDU 2066 一个人的旅行

    Description 虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗~),但是草儿仍然很喜欢旅行,因为在旅途中 会遇见很多人(白马王子,^0^),很多事,还能丰富自己的阅历,还 ...

  5. django之快速分页

    本文介绍djanog两种分页,第一是普通分页,第二是使用haystack全文检索的分页. 1.django自带分页功能,这个功能非常好用.基本知识点:Django提供了数据分页的类,这些类被定义在dj ...

  6. Linux入门之常用命令(13) crontab

    为当前用户创建cron服务 1.  键入 crontab  -e 编辑crontab服务文件 例如 文件内容如下: */2 * * * * /bin/sh /home/admin/jiaoben/bu ...

  7. css3动画:弹出式菜单

    css3动画:弹出式菜单 今天主要来讲讲transition和transform结合做的动画,会举一些现在(2017年)常见的动画例子. 注:本人也接触css3不久,如果写的有纰漏请指出,不喜勿喷. ...

  8. 【专章】dp基础

    知识储备:dp入门. 好了,完成了dp入门,我们可以做一些稍微不是那么裸的题了. ----------------------------------------------------------- ...

  9. hdu1356&hdu1944 博弈论的SG值(王道)

    S-NimProblem DescriptionArthur and his sister Caroll have been playing a game called Nim for some ti ...

  10. java中继承和组合的区别

    子类继承父类,父类的所有属性和方法都可以被子类访问和调用.组合是指将已存在的类型作为一个新建类的成员变量类型,又叫"对象持有". 通过组合和继承,都可以实现系统功能的重用和代码的复 ...