深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)
相关文章:
深入理解net core中的依赖注入、Singleton、Scoped、Transient(一)
深入理解net core中的依赖注入、Singleton、Scoped、Transient(二)
在上一节的学习中,我们已经知道了通过 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 = 0;
return scope =>
{
if (Interlocked.Increment(ref callCount) == 2)
{
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中的依赖注入、Singleton、Scoped、Transient(二)的更多相关文章
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)
相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(三)
相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(一)
相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transient(一) 深入理解net core中的依赖注入.Singleton.Scoped.Transient ...
- 深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)【转】
原文链接:https://www.cnblogs.com/gdsblog/p/8465401.html 相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transi ...
- 转 深入理解net core中的依赖注入、Singleton、Scoped、Transient
出处:http://www.mamicode.com/info-detail-2200461.html 一.什么是依赖注入(Denpendency Injection) 这也是个老身常谈的问题,到底依 ...
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
ASP.NET Core在启动以及后续针对每个请求的处理过程中的各个环节都需要相应的组件提供相应的服务,为了方便对这些组件进行定制,ASP.NET通过定义接口的方式对它们进行了"标准化&qu ...
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...
- ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理
ServiceProvider最终提供的服务实例都是根据对应的ServiceDescriptor创建的,对于一个具体的ServiceDescriptor对象来说,如果它的ImplementationI ...
- ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】
本系列前面的文章我们主要以编程的角度对ASP.NET Core的依赖注入系统进行了详细的介绍,如果读者朋友们对这些内容具有深刻的理解,我相信你们已经可以正确是使用这些与依赖注入相关的API了.如果你还 ...
随机推荐
- Zabbix3.2邮件告警python脚本
一.概述及环境要求 1.概述 zabbix监控也起到重要作用,以下是使用python脚本发送告警邮件配置方法.之前使用过sendemail邮件报警但是发现邮件主题为中文时候会出现乱码的问题. 2.环境 ...
- 【Canal源码分析】Canal Server的启动和停止过程
本文主要解析下canal server的启动过程,希望能有所收获. 一.序列图 1.1 启动 1.2 停止 二.源码分析 整个server启动的过程比较复杂,看图难以理解,需要辅以文字说明. 首先程序 ...
- linux把程序添加到全局环境变量
比如把, nginx服务放到全局变量 ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/ /usr/local/bin/就是环境变量目录
- Java虚拟机(四):JVM类加载机制
1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...
- HTML引入CSS样式的四种方法
在HTML中引入CSS的方法主要有四种,它们分别是行内式.内嵌式.链接式和导入式. 1.行内式 行内式是在标记的style属性中设定CSS样式.这种方式没有体现出CSS的优势,不推荐 ...
- ruby楼层排序问题
求教楼层排序问题 要求正确楼层排序为: B2,B1,1F,2F,3F...10F,11F 现有这13个无序的楼层 怎么排列成上面的格式? 求教 luikore 1楼 , 19小时前 1人喜欢 sort ...
- 网络爬虫(一):配置selenium、pycharm(windows平台)
最近在学习爬虫的编写,使用selenium模块时候,遇到了很多坑,本blog的目的是总结一下遇到的坑和解决办法,以便后来人少走弯路! 以下介绍均以Python3.x为基准进行,基于windows平台的 ...
- iOS开源项目周报0406
由OpenDigg 出品的iOS开源项目周报第十五期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. Tangra ...
- C#字符串中的中文逗号转英文逗号
public static string ToDBC(string input) { char[] c = input.ToCharArray(); for (int i = 0; i < c. ...
- HttpContext概念讲解
一:HttpContext理论知识: 1:HttpContext类它对Request.Respose.Server等等都进行了封装,并保证在整个请求周期内都可以随时随地的调用:为继承 IHttpMod ...