微软的实现3

微软的实现(3)

这个系列已经写了5篇,链接地址如下:

[Asp.net 5] DependencyInjection项目代码分析

[Asp.net 5] DependencyInjection项目代码分析2-Autofac

[Asp.net 5] DependencyInjection项目代码分析3-Ninject

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)

如果想对本篇有个更好的了解,建议需要先看

[Asp.net 5] DependencyInjection项目代码分析

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)

[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)”。

在之前的“上“、”中“俩篇已经介绍了ServiceTable、IGenericService、IService、IServiceCallSiteServiceEntryGenericServiceInstanceService、FactoryServiceService等类。本节主要介绍核心的”ServiceProvider“类。

IServiceProvider类

IServiceProvider类是微软这套DependencyInjection中直接对外的接口。而ServiceProvider是直接实现IServiceProvider并且对外直接提供功能的核心类。

对于ServiceProvider不仅要能够获取注入的类,还需要根据不同定义的范围获取不同范围的注入类。对于不同的范围(Transient、Scoped、Singleton),ServiceProvider需要使用不同的逻辑。我们简单分析下。

  • 对于Transient,每次都创建一个新的实例,所以代码中只需直接创建该注入类的实例即可,不需要对该类进行缓存;
  • 对于Singleton,全局只有一个实例,代码中可以将创建的对象缓存到静态的字典表中,之后每次需要该类型实例首先到全局静态字典表中去查找如果存在则直接返回,不存在创建后加入到字典表中,之后返回。(实际上源码中并未缓存到全局变量中,具体实现方式后面会讲解
  • 对于Scoped,每个Scope内是唯一的,不同Scope范围是不同的。这个就比较难实现。不过我们可以通过外部调用的代码简单的猜测下,之后我们通过查看源代码进行验证。

下面是不同Scoped范围的代码调用。

 CreateScope

我们可以根据不同Scoped的注入实例,实际上是通过获取不同的IServiceScope对象ServiceProvider属性,之后通过该属性创建。由于是不同的IServiceScope对象,我们可以大胆的假设IServiceScope对象的ServiceProvider属性也是不同的IServiceProvider对象。所以每个ServiceProvider对象内部,只需要维护一份注入对象的副本即可;由于IServiceScope对象实现了IDisposable接口(用在using上的对象,都实现了IDisposable接口,当using范围结束后,会自动调用IDisposable的Dispose方法),但注入的对象缓存在IServiceScope的ServiceProvider属性对象中,所以我们让ServiceProvider类也实现IDisposable接口,在IServiceScope的Dispose方法内部调用ServiceProvider类的Dispose方法即可。

通过上面的分析,我们可以大致想象出ServiceProvider类的定义,下面就是ServiceProvider类缩减的源代码:

internal class ServiceProvider : IServiceProvider, IDisposable
    {
        private readonly object _sync = new object();

        private readonly ServiceProvider _root;
        private readonly ServiceTable _table;

        private readonly Dictionary<IService, object> _resolvedServices = new Dictionary<IService, object>();
        private ConcurrentBag<IDisposable> _disposables = new ConcurrentBag<IDisposable>();

        public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors)
        {
            _root = this;
            _table = new ServiceTable(serviceDescriptors);

            _table.Add(typeof(IServiceProvider), new ServiceProviderService());
            _table.Add(typeof(IServiceScopeFactory), new ServiceScopeService());
            _table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table));
        }

        internal ServiceProvider(ServiceProvider parent)
        {
            _root = parent._root;
            _table = parent._table;
        }

        public object GetService(Type serviceType);

        public void Dispose()
        {
            var disposables = Interlocked.Exchange(ref _disposables, null);

            if (disposables != null)
            {
                foreach (var disposable in disposables)
                {
                    disposable.Dispose();
                }
            }
        }
}

对于ServiceProvider对象共有5个属性,

  • “_sync”是用于多线程同步的锁对象,我们可以不关心。
  • ServiceTable的“_table”对象,是内部维护注入类关系的字典表。
  • resolvedServices是用于维护在该范围内已经创建好的注入对象,当有该范围内的对象,首先会判断该字典表中是否存在实例,如果存在直接返回,不存在创建新的实例加入到该字典表中,并将该新创建的实例返回。
  • “disposables”是一个多线程支持的列表,从名字就看出这是调用Dispose后需要释放的对象。从Dispose方法也可以认证这点。(当注入的对象是实现了IDisposable接口,就需要在使用结束后调用其Dispose方法将其使用的关键资源释放掉,以免造成内存垃圾和资源浪费。)
  • ServiceProvider类型的“root”属性,这个.....(我估计十有八九会问这是什么鬼?难道ServiceProvider也是链形结构?但是那也不能叫root啊?难道是Singleton的实现,但是为毛不是全局的,而且每个ServiceProvider都有这个副本呢??)。经过参考其简单到鬼的注释,和反复试验发现确实是Singleton的实现。

ServiceProvider的Root属性展开

首先我们刚才没有注意到一个问题,就是ServiceProvider类定义不是public的,而是internal的。来我们回忆下类的定义:

internal class ServiceProvider : IServiceProvider, IDisposable

所以我们在外面是无法调用/构建ServiceProvider的实例的,只能在程序集范围内实例话。那在哪些地方调用该类的构造函数呢?
结果发现俩个构造函数都只被调用过一次。下面将调用的代码列出:

 ServiceProvider构造函数

  • 对于ServiceCollectionExtensions类调用的构造函数:这是对于IServiceCollection接口(继承自 IList<ServiceDescriptor>)的扩展,实际就是用IServiceCollection对象创建出ServiceProvider对象供外面调用。这是微软实现的依赖注入的入口。我们看使用IServiceCollection为参数的ServiceProvider构造函数,[_root=this]。说明新创建的ServiceProvider就是所谓的root。
  • 对于使用ServiceProvider为参数的ServiceProvider构造函数。[root=parent._root],说明通过该构造函数构造出的ServiceProvider对象和传入的ServiceProvider对象的_root实际指向同一块地址,并且都是使用 IServiceCollection创建的ServiceProvider对象[需要注意的是正常IServiceCollection.BuildServiceProvider只使用一次,虽然没有定义成全局唯一]。也就是说,使用IServiceCollection.BuildServiceProvider创建的ServiceProvider的作用域是全局的,使用ServiceProvider直接创建的scpoed范围的对象,也会成为全局的对象(没有时机调用其IDisposable接口)。

public ServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors)
        {
            _root = this;
            _table = new ServiceTable(serviceDescriptors);

            _table.Add(typeof(IServiceProvider), new ServiceProviderService());
            _table.Add(typeof(IServiceScopeFactory), new ServiceScopeService());
            _table.Add(typeof(IEnumerable<>), new OpenIEnumerableService(_table));
        }

        internal ServiceProvider(ServiceProvider parent)
        {
            _root = parent._root;
            _table = parent._table;
        }

ServiceProvider的属性我们已经讲完,那我们继续看下构造函数内其他的东西(上面的代码就是其构造函数)。我们发现ServiceTable内额外添加IServiceProvider、IServiceScopeFactory、IEnumerable<>的注入。

  • IServiceProvider的注入,说明能够创建新的IServiceProvider。我们上面说了只有俩个地方能够创建新的ServiceProvider,并且并不包含ServiceProviderService方法啊。实际上ServiceProviderService是之前介绍的IService, IServiceCallSite接口的实现类,当调用IServiceCallSite的方法” Invoke(ServiceProvider provider)“时,直接返回provider,并没有创建新的ServiceProvider(IServiceProvider)对象,而是使用现有的
  • IServiceScopeFactory注入,ServiceScopeService也是实现了IService, IServiceCallSite接口,并且内部会创建ServiceScopeFactory(IServiceScopeFactory)。
  • IEnumerable<>的注入,由于篇幅有限,将额外介绍,该处就略过了。

 ServiceProviderService

 ServiceScopeService、ServiceScopeFactory、ServiceScope

标签: DependencyInjection依赖注入

时间: 2024-10-23 11:19:00

微软的实现3的相关文章

微软要做用云量挖掘机,以技术驱动数字化转型快公司

今年7月,首次更名为"Inspire"的微软WPC全球合作伙伴大会上,微软宣布将所有与合作伙伴相关的角色都重新整合为一个新的部门:统一商业合作伙伴部门(One Commercial Partner),并进行了一整套的组织和流程改组,以适应云计算时代的用户需求与"用云量"规律. 2017年9月12日,微软大中华区副总裁.全球渠道事业部总经理.商业客户事业部总经理包嘉峰与媒体分享了这两个月微软商业合作伙伴部转型以来,微软自身所发生的变化以及为客户所带来的价值.根据包嘉峰

【2016-11-2】【坚持学习】【Day17】【微软 推出的SQLHelper】

从网络上找到 微软原版本的SQLHelper,很多行代码.认真看了,学习了. 代码: 1 using System; 2 using System.Data; 3 using System.Xml; 4 using System.Data.SqlClient; 5 using System.Collections; 6 7 namespace Helper 8 { 9 /// <summary> 10 /// The SqlHelper class is intended to encapsu

易宝典文章——玩转Office 365中的Exchange Online服务 之二十九 将垃圾邮件信息提供给微软

在反垃圾邮件这一无止境的永久工程中,如果只靠某一个人.某个公司或某个团体.组织的力量来进行往往是薄弱的,它需要整个Internet上的每一个人来参与.就如何在国内的骚扰电话.垃圾短信一样,往往需要防骚扰软件提供商都希望用户上报或标注垃圾短信发送号码和广告.骚扰电话的拨打号码,已针对这些号码进行更好的过滤.O365也提供了垃圾邮件信息反馈渠道,该操作能够让用户将其认为是垃圾邮件的邮件提交给微软,微软收到反馈后会对邮件进行分析,如果确实是垃圾邮件,微软会针对该邮件的特征在O365的反垃圾邮件系统中添

微软CodeDom模型学习笔记(全)

要点1 CodeDomProvider MSDN描述 CodeDomProvider可用于创建和检索代码生成器和代码编译器的实例.代码生成器可用于以特定的语言生成代码,而代码编译器可用于将代码编译为程序集. 注意:在 .NET Framework 2.0版中,在代码生成器和代码编译器中可用的方法可直接从代码提供程序获得.您不需要调用CreateGenerator 或CreateCompiler 来访问这些方法,这些方法被标记为已过时.这适用于预先存在的以及新的代码提供程序实现. CodeDomP

微软发布6月漏洞补丁 安全狗建议及时修复

北京时间6月10日凌晨,微软发布了2015年6月安全公告https://technet.microsoft.com/library/security/ms15-jun,本次更新共含8个补丁,其中2个级别为"严重",其余6个级别为"重要",主要修复了 Windows 系统.Office及IE浏览器等组件中的漏洞.服务器安全狗已经第一时间推送了安全更新,请及时修复安全狗提示给您的系统高危漏洞,避免漏洞被利用遭到攻击. 2015年6月微软安全公告简要如下: MS15-05

微软职位内部推荐-Senior Development Lead – Sharepoint

微软近期Open的职位: SharePoint is a multi-billion dollar enterprise business that has grown from an on-premises product that IT admins love into a core part of the Office 365 service today. Over the last several years, the SharePoint team has invested heavi

微软职位内部推荐-Software Engineer II

微软近期Open的职位: Job Title: Software Engineer II Location: Beijing, China Document Understanding and Task (DUT) team in STCA focuses on semantic understanding and answer recommendation platform and features for Bing, Cortana and Office. &nbsp Responsibil

微软职位内部推荐-Sr. SE - Office incubation

微软近期Open的职位: Senior Software Engineer-Office Incubation Office China team is looking for experienced engineers to improve consumer experience in China. Office has great products and features that are loved by users worldwide. We are looking for self-

微软 Windows 10 将支持 8 英寸以下 ARM 平板设备

2015 年 1 月 24 日,  9:32 下午 - 微软本周展示了 Windows 10 一系列新的改变,也包括首次公开展示的 Windows 10 手机版,但 ARM 平板并没有得到太多提及. 而且微软官方也确认驱动 ARM 平板的 Windows RT 操作系统将只有“特殊更新提供部分 Windows 10 功能”,意味着现有 Surface RT 和 Surface 2 和 Lumia 2550 用户可能享受不到 Windows 10 完整系统功能. 不过微软仍会支持 ARM 平板设备

微软职位内部推荐-SW Engineer II for WinCE

微软近期Open的职位: Do you have a passion for embedded devices and services? &nbsp Does the following make you excited: Embedded Systems, Industrial Automation and Control Systems? &nbsp If so, you need not look any further since these are a few segments