在上一节的学习中,我们已经知道了通过 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. Java实现Windows平台下Ping的最佳方法

    先上结论:通过调用系统自带的Ping命令来实现,使用exitValue()值来判断Ping的结果.按照惯例,0表示ok,1表示不通. private static void pingTest1() t ...

  2. 201521123064 《Java程序设计》第10周学习总结

    1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. ① 定义Thread类的子类,覆盖Thread类的run()方法,然后创建该子类的实例(一般不用该方法,开销 ...

  3. 201521123022 《Java程序设计》 第九周学习总结

    1.本章学习总结 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 Q1.1 截图你的提交结果(出现学号) Q1.2 自己以前编写的代码中经常出现什么异常.需要捕获吗(为什么)?应如何 ...

  4. 多线程面试题系列(7):经典线程同步 互斥量Mutex

    前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...

  5. lintcode.44 最小子数组

    最小子数组   描述 笔记 数据 评测 给定一个整数数组,找到一个具有最小和的子数组.返回其最小和. 注意事项 子数组最少包含一个数字 您在真实的面试中是否遇到过这个题? Yes 哪家公司问你的这个题 ...

  6. 纳税服务系统【用户模块之使用POI导入excel、导出excel】

    前言 再次回到我们的用户模块上,我们发现还有两个功能没有完成: 对于将网页中的数据导入或导出到excel文件中,我们是完全没有学习过的.但是呢,在Java中操作excel是相对常用的,因此也有组件供我 ...

  7. Spring @RequestParam乱码问题

    在网上找了很多资料才找到解决的方法,通过URL传递命名参数,后台接收的却是乱码解决方法如下: 方法一:将接收的参数重新编码 @RequestMapping(value="/handle&qu ...

  8. CSS 入门基础

    一.CSS 介绍什么是CSS CSS 指的是层叠样式表(Cascading StyleSheet).在网页制作时采用层叠样式表技术, 可以有效地对页面的布局.字体.颜色.背景和其它效果实现更加精确的控 ...

  9. js Date() 浏览器兼容问题解决

    一般 直接new Date() 是不会出现兼容性问题的,而 new Date(datetimeformatstring) 常常会出现浏览器兼容性问题,为什么,datetimeformatstring中 ...

  10. AngularJS -- Bootstrap(启动器)

    点击查看AngularJS系列目录 转载请注明出处:http://www.cnblogs.com/leosx/ Bootstrap(初始化) 这章介绍了Angular的初始化过程,以及如何在必要的时候 ...