Core官方DI解析(5)-ServiceProviderEngine
最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine
在ServiceProvider
的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先来看一下IServiceProviderEngine
接口和其实现类的整体结构
IServiceProviderEngine类型继承关系
internal interface IServiceProviderEngine : IDisposable, IServiceProvider
{
IServiceScope RootScope { get; }
}
`IServiceProvderEngine这个接口`继承了`IServiceProvider`接口,也就是说工作引擎也具有**GetService()**方法,在此接口中具有一个`IServiceScope`类型的**RootScope**,而这个属性则代表是**根容器**
`IServiceScope`代表一个容器接口,这个接口中具有一个`IServiceProvider`类型的属性,返回真正表示容器的一个`IServiceProvider`类型
public interface IServiceScope : IDisposable
{
/// <summary>
/// The <see cref="System.IServiceProvider"/> used to resolve dependencies from the scope.
/// </summary>
IServiceProvider ServiceProvider { get; }
}
IServiceProviderEngine整体结构
IServiceProviderEngine
- ServiceProviderEngine
- CompiledServiceProviderEngine
- DynamicServiceProviderEngine
- RuntimeServiceProviderEngine
- ILEmitServiceProviderEngine
- ExpressionsServiceProviderEngine
上面是目前整个引擎结构,但是前面说过目前只用到了`DynamicServiceProviderEngine`,但是我们看整个类型会看到其实在这几个派生类型中只有一个实现方法`RealizeService(ServiceCallSite callSite)`,而整体结构都是在基类`ServiceProviderEngine`类型中,下面来看看这个基类类型
ServiceProviderEngine
`ServiceProviderEngine`类型是整个结构的核心类型,但是这个类也是一个很简单的类,这个类只是调用`CallSiteFactory`和`CallSiteRuntimeResolver`,由下图可以看到这个类型是一个抽象类,并且实现了`IServiceProviderEngine`和`IServiceScopeFactory`接口接口
`IServiceScopeFactory`这个接口提供了一个创建子容器方法我们已知道`IServiceProviderEngine`接口*继承*了`IServiceProvider`接口,那么也就是说在`ServiceProviderEngine`已经具备以下两个功能
1.获取服务实例对象
2.创建子容器
internal abstract class ServiceProviderEngine : IServiceProviderEngine, IServiceScopeFactory{}
// 创建子容器接口
public interface IServiceScopeFactory
{
//
IServiceScope CreateScope();
}
下面首先来看一下此类中拥有的字段+属性,这些属性都是在构造器中进行了实例化
_callback:
这个字段就是顶级容器时检查scoped生命周期的访问者对象,这个从
ServiceProvider
类中时进行传入的,在这里并不细讲这个类型RealizedServices:
这个属性是缓存根据容器获取服务实例对象委托,其中Key为ServiceType
_createServiceAccessor:
这是一个根据类型获取一个根据容器获取服务实例对象的委托,可以看到使用了一个CreateServiceAccessor()进行赋值,CreateServiceAccessor()是此类型的一个核心方法,下面介绍
CallSiteFactory:
ServiceCallSite
工厂类型,在构造器中实例化,可以看到实例化时将serviceDescriptors进行传入,并且可以看到在构造器中向此实例对象中添加了一个IServiceProvider
和IServiceScopeFactory
RuntimeResolver:
这个属性是是获取服务实例的访问者对象,可以看到在构造器中进行传入
Root:
Root代表是一个顶级容器
ServiceProviderEngineScope
类型则是一个具体的容器类型,这个类型中缓存了所有的具体服务实例对象,这个类型实现了IServiceScope
接口,从下面代码可以看到RootScope
其实就是直接返回了Root
属性RootScope:
这也是一个根容器实例对象,直接返回的Root属性
// 顶级容器时scoped生命周期实例检查策略
private readonly IServiceProviderEngineCallback _callback;
// 根据类型创建构建服务的委托
private readonly Func<Type, Func<ServiceProviderEngineScope, object>> _createServiceAccessor;
// 此实例是否被销毁
private bool _disposed;
// 缓存根据容器获取服务实例的委托, Key为注册类型
internal ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>> RealizedServices { get; }
// CallSite工厂类属性,此类型用于根据指定实例化方式来创建对应的CallSite
internal CallSiteFactory CallSiteFactory { get; }
// 访问者对象,此对象对进行实例和缓存具体真正的对象
protected CallSiteRuntimeResolver RuntimeResolver { get; }
// 根容器实例属性
public ServiceProviderEngineScope Root { get; }
// 根容器实例属性
public IServiceScope RootScope => Root;
// 构造器
protected ServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback)
{
_createServiceAccessor = CreateServiceAccessor;
_callback = callback;
// 实例化根容器
Root = new ServiceProviderEngineScope(this);
// 实例化 CallSite对象访问者对象
RuntimeResolver = new CallSiteRuntimeResolver();
// 实例化CallSiteFactory类型对象
CallSiteFactory = new CallSiteFactory(serviceDescriptors);
CallSiteFactory.Add(typeof(IServiceProvider), new ServiceProviderCallSite());
// 缓存一个ServiceScopeFactoryCallSite服务,相当于缓存一个ServiceProviderEngine,根据此对象进行创建子容器
CallSiteFactory.Add(typeof(IServiceScopeFactory), new ServiceScopeFactoryCallSite());
// 缓存实例化对象的工厂
RealizedServices = new ConcurrentDictionary<Type, Func<ServiceProviderEngineScope, object>>();
}
`ServiceProviderEngine`类型中方法只有**GetService()**,**CreateScope()**,**CreateServiceAccessor()**,**Dispose()**和一个抽象方法**RealizeService()**,其中几个派生类中都只是实现了**RealizeService()**,这个一会再看,下面来看看`ServiceProviderEngine`类中的这几个方法
RealizeService:
这个方法由派生类继承,由指定的
ServiceCallSite
缓存并获取 服务实例的委托GetService:
这个方法获取服务实例对象,可以看到具有两个此方法,并且第一个调用了第二个,并将顶级容器Root进行了传入,而在第二个方法中,获取并添加_createServiceAccessor委托,然后调用此委托进行获取服务实例
CreateScope:
这个方法是创建一个子容器对象,在这个方法中可以看到直接 new 了一个容器对象,并将当前对象进行了传入。从此可以得知为什么所有容器共享顶级容器的服务注册了
Dispose:
清除当前对象,并清除顶级容器
CreateServiceAccessor:
这个方法可以看到根据ServiceType进行获取指定
ServiceCallSite
,然后再调用派生类实现的RealizeService()进行返回
// 抽象类型,子类实现
protected abstract Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite);
public object GetService(Type serviceType) => GetService(serviceType, Root);
internal object GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
{
if (_disposed)
ThrowHelper.ThrowObjectDisposedException();
// 添加并获取根据容器对象实例化对象的方法,其方法由子类进行重写
var realizedService = RealizedServices.GetOrAdd(serviceType, _createServiceAccessor);
// 验证是否允许进行实例化对象
_callback?.OnResolve(serviceType, serviceProviderEngineScope);
return realizedService.Invoke(serviceProviderEngineScope);
}
public void Dispose()
{
_disposed = true;
Root.Dispose();
}
// 实例化的子容器
public IServiceScope CreateScope()
{
if (_disposed)
ThrowHelper.ThrowObjectDisposedException();
return new ServiceProviderEngineScope(this);
}
private Func<ServiceProviderEngineScope, object> CreateServiceAccessor(Type serviceType)
{
// 根据基类类型获取对应的CallSite
var callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain());
if (callSite != null)
{
// 缓存当前注册
_callback?.OnCreate(callSite);
return RealizeService(callSite);
}
return _ => null;
}
DynamicServiceProviderEngine和CompiledServiceProviderEngine
下面来看一下`DynamicServiceProviderEngine`和`CompiledServiceProviderEngine`这两个派生类型,从上面继承关系可以看到这两个派生类型是一个继承关系 `DynamicServiceProviderEngine`继承于`CompiledServiceProviderEngine`.
internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine{}
在这两个派生类型中都只是实现了基类的RealizeService(),下面先来看看CompiledServiceProviderEngine
类的实现
可以看到CompiledServiceProviderEngine
类中具有一个ExpressionResolverBuilder
对象,这个类是使用表达式树生成结构,这个实例在构造函数进行创建,并且将CallSiteRuntimeResolver
对象,本对象和顶级容器进行了传入,可以看到在重写的方法中是调用了ExpressionResolverBuilder
对象的Build()
,这个方法会生成一个Func<ServiceProviderEngineScope,Object>委托,然后缓存此委托,
注:
ExpressionResolverBuilder
这个类挺复杂,我也没看懂,所以在此不介绍,有兴趣的可以直接看源码
internal abstract class CompiledServiceProviderEngine : ServiceProviderEngine
{
// 表达式树生成对象
public ExpressionResolverBuilder ExpressionResolverBuilder { get; }
// 构造函数
public CompiledServiceProviderEngine(IEnumerable<ServiceDescriptor> serviceDescriptors, IServiceProviderEngineCallback callback) : base(serviceDescriptors, callback)
=> ExpressionResolverBuilder = new ExpressionResolverBuilder(RuntimeResolver, this, Root);
// 重写RealizeService方法
protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
// 使用表达式树进行创建一个Func<ServiceProviderEngineScope,Object>委托
var realizedService = ExpressionResolverBuilder.Build(callSite);
// 直接将表达式生成的委托进行替换之前的缓存
RealizedServices[callSite.ServiceType] = realizedService;
return realizedService;
}
}
而在`RuntimeServiceProviderEngine`类中,则只是实现了**RealizeService()**,从下面代码可以看出在第一次调用时是直接调用`CallSiteRuntimeResolver`这个访问者获取的实例数据,而在第二次才调用的基类,也就是`CompiledServiceProviderEngine`进行了缓存,但是至于为什么这样干,我没有弄清。。。
internal class DynamicServiceProviderEngine : CompiledServiceProviderEngine
{
public DynamicServiceProviderEngine(
IEnumerable<ServiceDescriptor> serviceDescriptors,
IServiceProviderEngineCallback callback)
: base(serviceDescriptors, callback)
{
}
protected override Func<ServiceProviderEngineScope, object> RealizeService(ServiceCallSite callSite)
{
var callCount = 0;
return scope =>
{
if (Interlocked.Increment(ref callCount) == 2)
{
// 如果当前是第二次调用,则调用父级进行缓存
Task.Run(() => base.RealizeService(callSite));
}
// 调用访问者进行根据当前容器和CallSite进行实例化服务对象
return RuntimeResolver.Resolve(callSite, scope);
};
}
}
Core官方DI解析(5)-ServiceProviderEngine的更多相关文章
- Core官方DI解析(3)-ServiceCallSite.md
上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...
- Core官方DI解析(4)--CallSiteRuntimeResolver
CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用 ...
- Core官方DI解析(2)-ServiceProvider
ServiceProvider ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServ ...
- Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类
前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...
- abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析
老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...
- Asp.Net Core中DI的知识总结
在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...
- asp.net core的DI框架思考以及服务实例的获取方式总结
转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...
- 实战Asp.Net Core:DI生命周期
title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...
- 阅读DMA Controller Core 官方手册
阅读DMA Controller Core 官方手册 DMA控制器框架图 怎样去设定一个DMA控制器 实例化DMA控制器 参数配置界面如下图所示: 对于width of the DMA length ...
随机推荐
- JAVA中AWT编程
JAVA使用AWT和Swing 类完成图形用户界面编程,AWT全称是抽象窗口工具集(Abstract Window Toolkit),它是最早的sun提供的GUI库(Graphics User Int ...
- AI应用开发实战 - 从零开始配置环境
AI应用开发实战 - 从零开始配置环境 与本篇配套的视频教程请访问:https://www.bilibili.com/video/av24421492/ 建议和反馈,请发送到 https://gith ...
- 解决 HomeBrew 下载缓慢的问题
macOS 自身不提供包管理器,常用的包管理器有 HomeBrew MacPorts MacPorts 第一次使用要 build 整个基本库,编译时间很长.优点是不怎么依赖系统,更新 macOS 不会 ...
- Kubernetes 笔记 09 DaemonSet 我是一只看门狗
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. Hi,大家好, ...
- .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9977862.html 写在前面 千呼万唤始出来,首先,请允许我长吸一口气!真没想到一份来自28岁老程序员 ...
- pycharm安装svn插件
弄了svn的服务端和客户端,为了方便我pycharm的使用,我又在pycharm里进行了配置,要用到subversion 下载 https://sourceforge.net/projects/win ...
- java~lambda表达式让查询更优雅
在java之前的版本里,如果希望从集合时查找符合条件的数据,如果先遍历他,这种写法是我们不能接受的,所以现在java有了lambda就很好的解决了这个问题,让代码更优雅一些! /** * lambda ...
- .netcore 模块积累
最全的 demo https://github.com/XiaoFaye/netcore-samples http://files.cnblogs.com/files/kellynic/practic ...
- Python3中列表字符串转数字
比如我们有个列表: number = [']; 如果我们需要将列表里的元素转换为数字呢?最常用的大家可能会想到使用列表推导式: number = ['] number = [int(x) for x ...
- 【Tomcat】Tomcat工作原理及简单模拟实现
Tomcat应该都不陌生,我们经常会把写好的代码打包放在Tomcat里并启动,然后在浏览器里就能愉快的调用我们写的代码来实现相应的功能了,那么Tomcat是如何工作的? 一.Tomcat工作原理 我们 ...