Core官方DI解析(2)-ServiceProvider
ServiceProvider
ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServiceProviderEngine实现类中
ServiceProvider还具有一个扩展类型ServiceProviderServiceExtensions,在扩展类型之中实现了一些我们经常使用的获取服务实例方法,比如GetServices()和GetRequiredService()方法,还实现了获取子容器方法CreateScope(),下面来具体的看一下这个类型
从下面代码看到ServiceProvider一个实现了三个接口
- IServiceProvider 获取服务接口,这个接口是位于
System程序集下的,而这个接口只有一个object GetService(Type serviceType)方法,也就是说我们常用很多方法包括泛型获取都是来自于扩展类中- IDisposable 说明此对象需要被释放
- IServiceProviderEngineCallback 这个接口就是检验
validateScopes时使用的,接口具有两个方法OnCreate()和OnResolve()分别用于创建服务实例时缓存和校验,
public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
{}
ServiceProvider这个类型其实挺简单,从下面代码中GetService()方法可以看出它只是代理了一个IServiceProviderEngine实现类型,
_engine: 作为一个
IServiceProviderEngine接口,这个接口是ServiceProvider的工作引擎接口,也是一个核心类型,下一章再详细讲解这个接口及其实现类型_callSiteValidator: 这是一个验证ValidateScopes的缓存类型(访问者模式),可以看到,在构造函数中只有当ValidateScopes为true时才实例化此对象,然后在获取服务实例时通过OnCreate()进行缓存和通过OnResolve()进行校验
ServiceProvider的实例化方式在上一章已经说过,利用ServiceDescriptor集合和ServiceProviderOptions进行实例化,可以看到,在构造方法中首先通过ValidateScopes属性来进行实例化CallSiteValidator和将当前对象赋值给IServiceProviderEngineCallback类型变量
将this赋值给IServiceProviderEngineCallback是为了让IServiceProviderEngine进行调用验证
然后通过ServiceProviderMode这个枚举进行判断实例化的具体引擎对象,四个枚举对应四种引擎对象,前面已经说过目前DI只使用了Dynamic这一种,下面说IServiceProviderEngineCallback时也只说这一种
public sealed class ServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback
{
// ServiceProvider工作引擎接口
// 这个接口是一个核心接口
// 使用这个接口的子类进行调用缓存各种注册服务和调用访问者对象进行获取实例对象
private readonly IServiceProviderEngine _engine;
/// 此属性缓存当前注册类型,当ServiceProviderOptions.ValidateScopes为true进行验证
private readonly CallSiteValidator _callSiteValidator;
internal ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options)
{
IServiceProviderEngineCallback callback = null;
if (options.ValidateScopes)
{
callback = this;
_callSiteValidator = new CallSiteValidator();
}
// 根据ServiceProviderMode进行实例化对应的工作引擎类型
switch (options.Mode)
{
case ServiceProviderMode.Dynamic:
// 实例化 DynamicServiceProviderEngine
_engine = new DynamicServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Runtime:
_engine = new RuntimeServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.ILEmit:
_engine = new ILEmitServiceProviderEngine(serviceDescriptors, callback);
break;
case ServiceProviderMode.Expressions:
_engine = new ExpressionsServiceProviderEngine(serviceDescriptors, callback);
break;
default:
throw new NotSupportedException(nameof(options.Mode));
}
}
/// 获取指定类型的服务对象
public object GetService(Type serviceType) => _engine.GetService(serviceType);
public void Dispose() => _engine.Dispose();
void IServiceProviderEngineCallback.OnCreate(ServiceCallSite callSite)
=>_callSiteValidator.ValidateCallSite(callSite);
void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope)
=>_callSiteValidator.ValidateResolution(serviceType, scope, _engine.RootScope);
}
ServiceProviderServiceExtensions
前面说过这个类是ServiceProvider的扩展类型,提供了更佳便捷,下面就来看看这个这个扩展类提供的方法
在这个扩展类中就扩展了GetRequiredService(),GetServices()和CreateScope()三个方法,前两个也是获取服务实例,第三个获取一个子IServiceProvider,也就是说获取一个子容器
GetRequiredService()方法是如果获取的当前类型并没有被注册,那么就会抛出InvalidOperationException异常,从下面代码可以看出,GetRequiredService()方法首先判断当前ServicePrivider是否是ISupportRequiredService的实现类,如果是,则就返回自身的GetRequiredService()方法,如果不是,就直接调用GetService(),如果返回服务实例为NULL,就抛出异常.
ISupportRequiredService接口中只定义了GetRequiredService(),然而现在的ServiceProvider类型并没有实现ISupportRequiredService接口
GetServices()方法是获取当前类型的所有服务实例,可以看到这个方法无非是调用的GetRequiredService(),只不过参数是一个IEnumerable集合,在内部使用IEnumerable参数获取服务实例是一个特殊处理,这个在后面就可以看到
CreateScope()方法是一个获取子类容器的,获取方式从下面代码看的也是通过服务注册的方式获取服务实例,也就是说内部进行了注册,这个注册是在ServiceProviderEngine类中
public static class ServiceProviderServiceExtensions
{
// 泛型重载
public static T GetService<T>(this IServiceProvider provider)
=> (T)provider.GetService(typeof(T));
// 如果当前服务并未注册,则会抛出异常
public static object GetRequiredService(this IServiceProvider provider, Type serviceType)
{
// 如果当前ServiceProvider实现了 ISupportRequiredService
// 则直接调用当前ServiceProvier的GetRequiredService获取服务实例
var requiredServiceSupportingProvider = provider as ISupportRequiredService;
if (requiredServiceSupportingProvider != null)
return requiredServiceSupportingProvider.GetRequiredService(serviceType);
// 如果当前ServiceProvider未实现ISupportRequiredService
// 就直接调用GetService获取服务实例,但是如果服务实例为空,则抛出异常
var service = provider.GetService(serviceType);
if (service == null)
throw new InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType));
return service;
}
// 泛型版本
public static T GetRequiredService<T>(this IServiceProvider provider)
=> (T)provider.GetRequiredService(typeof(T));
// 获取指定注册类型<T>的所有服务实例
public static IEnumerable<T> GetServices<T>(this IServiceProvider provider)
=> provider.GetRequiredService<IEnumerable<T>>();
// 同上,
public static IEnumerable<object> GetServices(this IServiceProvider provider, Type serviceType)
{
// 制造一个serviceType类型的IEnumberable<>集合,serviceTypele类型作为当前集合的泛型参数
var genericEnumerable = typeof(IEnumerable<>).MakeGenericType(serviceType);
return (IEnumerable<object>)provider.GetRequiredService(genericEnumerable);
}
// 创建一个子IServiceProvider实例
// 内部其实将IServiceScopeFactory接口和一个ServiceScopeFactoryCallSite进行了注册
// 这个是在IServiceProviderEngine的实现类ServiceProviderEngine中的,以后在详细介绍
public static IServiceScope CreateScope(this IServiceProvider provider)
=> provider.GetRequiredService<IServiceScopeFactory>().CreateScope();
}
Core官方DI解析(2)-ServiceProvider的更多相关文章
- Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类
前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...
- Core官方DI解析(3)-ServiceCallSite.md
上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...
- Core官方DI解析(4)--CallSiteRuntimeResolver
CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用 ...
- Core官方DI解析(5)-ServiceProviderEngine
最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine在ServiceProvider的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先 ...
- 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 ...
随机推荐
- 使用 connect http proxy 绕过 ssh 防火墙限制
1.安装 connect brew install connect 2.配置 ~/.ssh/config Host * ProxyCommand connect -H your.proxy.serve ...
- 基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)
基于python语言的tensorflow的‘端到端’的字符型验证码识别 1 Abstract 验证码(CAPTCHA)的诞生本身是为了自动区分 自然人 和 机器人 的一套公开方法, 但是近几年的 ...
- Linux 桌面玩家指南:15. 深度学习可以这样玩
特别说明:要在我的随笔后写评论的小伙伴们请注意了,我的博客开启了 MathJax 数学公式支持,MathJax 使用$标记数学公式的开始和结束.如果某条评论中出现了两个$,MathJax 会将两个$之 ...
- Base64编码的原理
Base64是一种基于64个可打印字符来表示二进制数据的表示方法.由于 2的6次方是64,所以每6个比特为一个单元,对应某个可打印字符.3个字节有24个比特,对应于4个Base64单元,即3个字节可由 ...
- 一个适合.NET Core的代码安全分析工具 - Security Code Scan
本文主要翻译自Security Code Scan的官方Github文档,结合自己的初步使用简单介绍一下这款工具,大家可以结合自己团队的情况参考使用.此外,对.NET Core开发团队来说,可以参考张 ...
- C# 《编写高质量代码改善建议》整理&笔记 --(三)泛型&委托&事件
1.泛型 基于泛型,我们可以将类型参数化,以便更大范围地进行代码复用.同时,它减少了泛型类及泛型方法中的转型, 确保类型安全. 1)总是优先考虑泛型 优点:可重用性,类型安全,高效率. 2)避免在泛型 ...
- SpringSecurity设置角色和权限的注意点
概念 在UserDetailsService的loadUserByUsername方法里去构建当前登陆的用户时,你可以选择两种授权方法,即角色授权和权限授权,对应使用的代码是hasRole和hasAu ...
- springboot~maven制作底层公用库
把一些公用方法,类型抽象到一个项目里,让其它项目依赖它,这种设计是一种解耦的体现,其实像springboot就是我们的一种依赖,他里面有很多子模块,用到哪个就添加哪个依赖即可,像redis,mongo ...
- 使用Atlas进行元数据管理之Glossary(术语)
背景:笔者和团队的小伙伴近期在进行数据治理/元数据管理方向的探索, 在接下来的系列文章中, 会陆续与读者们进行分享在此过程中踩过的坑和收获. 元数据管理系列文章: [0] - 使用Atlas进行元数据 ...
- 你觉得 .NET 性能低,可能只是因为你的能力低
by Conmajia 本文由以下大佬赞助 加入赞助者行列 {{ sponsor.name }} 感恩,你们的赞助让我在抓耳挠腮写文章时不至于断了香烟. var s = [{ name: '◎梦想起航 ...