解析 .Net Core 注入 (2) 创建容器
在上一节的学习中,我们已经知道了通过 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) 创建容器的更多相关文章
- 解析 .Net Core 注入 (1) 注册服务
在学习 Asp.Net Core 的过程中,注入可以说是无处不在,对于 .Net Core 来说,它是独立的一个程序集,没有复杂的依赖项和配置文件,所以对于学习 Asp.Net Core 源码的朋友来 ...
- 解析 .Net Core 注入——注册服务
在学习 Asp.Net Core 的过程中,注入可以说是无处不在,对于 .Net Core 来说,它是独立的一个程序集,没有复杂的依赖项和配置文件,所以对于学习 Asp.Net Core 源码的朋友来 ...
- 解析 .Net Core 注入 (3) 创建对象
回顾 通过前两节的学习,我们知道 IServiceCollection 以元数据(ServiceDescriptor)的形式存放着用户注册的服务,它的 IServiceCollection 的拓展方法 ...
- .Net Core 注入学习——注册服务
解析 .Net Core 注入——注册服务发表于:2017-10-23 10:47 作者:行走即歌 来源:51Testing软件测试网采编字体:大 中 小 | 上一篇 | 下一篇 |我要投稿 | 推荐 ...
- .NET CORE学习笔记系列(2)——依赖注入[4]: 创建一个简易版的DI框架[上篇]
原文https://www.cnblogs.com/artech/p/net-core-di-04.html 本系列文章旨在剖析.NET Core的依赖注入框架的实现原理,到目前为止我们通过三篇文章从 ...
- Docker 为 ASP.NET Core WebApi 应用程序生成 Docker 映像,创建容器并运行
1.使用VS2017新建ASP.NET Core WebApi项目 选择API启用Docker支持 2.为 ASP.NET Core WebApi 应用程序生成 Docker 映像,并创建容器运行 生 ...
- 翻译-在10行代码之内创建容器化的.net core应用
本文翻译自Hans Kilian的文章 Creating a containerized .NET core application in less than 10 lines of code htt ...
- 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表
创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表 创建数据模型类(POCO类) 在Models文件夹下添 ...
- .net core 注入机制与Autofac
本来是要先出注入机制再出 管道 的,哈哈哈……就是不按计划来…… 这里扯扯题外话:为什么要注入(DI,dependency-injection),而不用 new 对象? 可能我们都很清楚,new 对象 ...
随机推荐
- 201521123122 《java程序设计》 第四周学习总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 这个思维导图比较简单,详细内容点击此处 2. 书面作业 注释的应用 使用类的注释与方法的注释 ...
- 201521123002 《Java程序设计》第2周学习总结
<Java程序设计>第2周学习总结 1. 本章学习总结 String 1.String类的对象是不可变(immutable)的 2.拼接(+号) "PG"+13; (一 ...
- 201521123062《Java程序设计》第1周学习总结
1.本章学习总结 认识Java平台运行环境,运行软件 初步认识JDK,JRE,JVM基本含义 书面作业 1.为什么java程序可以跨平台运行?执行java程序的步骤是什么? Java平台运行在各平台的 ...
- python3中的一些小改动
Python 3.3中使用print是必须要括号因为在python3以上的版本中print不再是一条命令而是一个函数了.
- 201521123072《java程序设计》第十周学习总结
201521123072<java程序设计>第十周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异 ...
- Selenium_WebDriver_元素方法
版权声明:本文为博主原创文章,转载请注明出处. 前面已经学习了定位元素,定位只是第一步,定位之后需要对这个元素进行操作,如在百度搜索首页的输入框进行输入文本,对"百度一下"按钮进行 ...
- 如何查看maven plugin所包含的goal
maven项目的构建生命周期(build lifecycle)由很多阶段组成:从validate到deploy. maven插件中包含goal.这些goal可以被绑定到不同的maven的构建阶段上.g ...
- Linux Ubuntu从零开始部署web环境及项目 -----部署项目 (三)
上一篇讲了如何在linux搭建web环境,这边将如何部署项目. 1,打包项目包 2,上传项目包 将.war项目包通过xftp上传到tomcat目录wabapps目录下 3,启动项目 通过xshell命 ...
- JS设计模式(三) 数据访问对象模式
引言 HTML5 提供了两种在客户端存储数据的新方法:localStorage.sessionStorage,他们是Web Storage API 提供的两种存储机制,区别在于前者属于永久性存储,而后 ...
- QT_FORWARD_DECLARE_CLASS
相当于class 类名. 那么他和#include 包含头文件有什么区别呢 首先我们为什么要包括头文件问题的回答很简单通常是我们需要获得某个类型的定义(definition).那么接下来的问题 ...