CallSiteRuntimeResolver类型是一个创建或获取服务实例的类型,这个类型继承了CallSiteVisitor<TArgument, TResult>这个类型,也是使用了访问者模式,下面一一来解析此类

ServiceProviderEngineScope

在解析`CallSiteRuntimeResolver`之前先看一下`ServiceProviderEngineScope`类型,这个类型就可以是一个容器类型,最后实例化的服务对象就缓存在此类之中,

从下面代码中可以看出此类实现了`IServiceScope`和`IServiceProvider`两个接口,并且此类型拥有两个字段

_disposables:IDisposabl集合,此字段缓存的时所有实现了IDisposable接口的注册服务,以便在释放此容器实例时并将这些服务一起释放

_disposed:判断此属性是否已被是否释放

internal class ServiceProviderEngineScope : IServiceScope, IServiceProvider
{
private List<IDisposable> _disposables;
private bool _disposed;
}
在此类中还具有两个属性,一个是缓存实例对象的集合和一个**ServiceProviderEngine**类型的属性,从下面可以看出缓存集合使用了是`ServiceCacheKey`作为缓存的key,

而Engine是引擎类型,此属性通过构造函数传入,并且所有容器共享一个`ServiceProviderEngine`,也就是共享容器共享注册的服务
//    缓存的实例对象集合
internal Dictionary<ServiceCacheKey, object> ResolvedServices { get; } = new Dictionary<ServiceCacheKey, object>();
// 所有ServiceProviderEngineScope对象共享一个ServiceProviderEngine
public ServiceProviderEngine Engine { get; } // 构造函数
public ServiceProviderEngineScope(ServiceProviderEngine engine)=> Engine = engine;
这个类中一共具有四个方法,
  • GetService():获取对象,可以看到此方法调用的EngineGetService(),这个方法到ServiceProviderEngine时再看
  • ServiceProvider():这个方法返回的是当前对象
  • Dispose():释放当前容器,可以看到在释放当前容器时会把_disposables集合中所有实例进行释放,并把_disposed属性设置TRUE
  • CaptureDisposable():这个方法缓存要被的释放的服务实例
public object GetService(Type serviceType)
{
if (_disposed)
// 如果已被释放,就不能调用此方法
ThrowHelper.ThrowObjectDisposedException();
return Engine.GetService(serviceType, this);
} public IServiceProvider ServiceProvider => this; public void Dispose()
{
lock (ResolvedServices)
{
if (_disposed)
return;
_disposed = true;
if (_disposables != null)
{
for (var i = _disposables.Count - 1; i >= 0; i--)
{
var disposable = _disposables[i];
disposable.Dispose();
} _disposables.Clear();
} ResolvedServices.Clear();
}
}
// 缓存所有需要清理的服务实例
internal object CaptureDisposable(object service)
{ if (!ReferenceEquals(this, service))
{
if (service is IDisposable disposable)
{
lock (ResolvedServices)
{
if (_disposables == null)
_disposables = new List<IDisposable>();
_disposables.Add(disposable);
}
}
}
return service;
}

CallSiteRuntimeResolver

​ 上面说过CallSiteRuntimeResolver这个类型是创建和获取服务实例类型的访问者,这个类型泛型参数分别为RuntimeResolverContext类型和实例对象类型Object

internal sealed class CallSiteRuntimeResolver : CallSiteVisitor<RuntimeResolverContext, object>{}

RuntimeResolverContext类型是一个ServiceProviderEngineScope封装类型,这个类型中具有一个ServiceProviderEngineScope类型属性和一个RuntimeResolverLock枚举类型属性,这个枚举类型在实例化对象时当做了锁使用

internal struct RuntimeResolverContext
{
public ServiceProviderEngineScope Scope { get; set; }
// 锁
public RuntimeResolverLock AcquiredLocks { get; set; }
}
[Flags]
internal enum RuntimeResolverLock
{
Scope = 1,
Root = 2
}

CallSiteRuntimeResolver类型中拥有两类方法,

  • 根据注册服务的生命周期进行访问服务实例对象
  • 根据ServiceCallSite的设置类型进行访问服务实例对象

这两个类都在其CallSiteVisitor<TArgument, TResult>基类中

//		根据服务对象的生命周期进行访问访问实例
protected virtual TResult VisitCallSite(ServiceCallSite callSite, TArgument argument)
{
// 缓存位置由ServiceCallSite内部的Cache属性的Location提供
switch (callSite.Cache.Location)
{
case CallSiteResultCacheLocation.Root:
return VisitRootCache(callSite, argument);
case CallSiteResultCacheLocation.Scope:
return VisitScopeCache(callSite, argument);
case CallSiteResultCacheLocation.Dispose:
return VisitDisposeCache(callSite, argument);
case CallSiteResultCacheLocation.None:
return VisitNoCache(callSite, argument);
default:
throw new ArgumentOutOfRangeException();
}
} // 根据其ServiceCallSite的Kind属性访问服务对象
protected virtual TResult VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
{
switch (callSite.Kind)
{
case CallSiteKind.Factory:
return VisitFactory((FactoryCallSite)callSite, argument);
case CallSiteKind.IEnumerable:
return VisitIEnumerable((IEnumerableCallSite)callSite, argument);
case CallSiteKind.Constructor:
return VisitConstructor((ConstructorCallSite)callSite, argument);
case CallSiteKind.Constant:
return VisitConstant((ConstantCallSite)callSite, argument);
case CallSiteKind.ServiceProvider:
return VisitServiceProvider((ServiceProviderCallSite)callSite, argument);
case CallSiteKind.ServiceScopeFactory:
return VisitServiceScopeFactory((ServiceScopeFactoryCallSite)callSite, argument);
default:
throw new NotSupportedException($"Call site type {callSite.GetType()} is not supported");
}
}

​这两个方法内部调用的方法部分被CallSiteRuntimeResolver类中重写,

下面先来看看根据生命周期进行访问的一系列方法

  • VistRootCache:

    这个方法是访问Root生命周期的方法,可以看到这个在这个方法调用了一个VisitCache(),这个方法一共四个参数,第一个,第二个分别是当前方法函数。第三个参数代表容器对象,容器使用的是ServiceProviderEngine实例中的Root属性,这个容器代表了顶级容器,这也就是Root生命周期的本质,使用的顶级容器进行创建/获取实例,第四个参数锁,此方法使用的是RuntimeResolverLock.Root

  • VisitScopeCache:

    这个方法是访问Scoped生命周期方法,此方法和上面方法相似,也是调用了VisitCache(),但是不同的是是锁不同,这个锁是根据当前容器来决定,如果当前容器为顶级容器,就使用Root锁,所以不为顶级容器,则使用Scope

  • VisitDisposeCache

    这个方法访问transient生命周期方法,可以看到这个方法直接调用VisitCallSiteMain()进行获取实例对象,然后调用CaptureDisposable()将此对象尝试缓存到ServiceProviderEngineScope容器的_disposables集合中

  • VisitNoCache

    这个方法代表不缓存,这个方法在CallSiteRuntimeResolver类中未重写,所以直接调用的CallSiteVisitor类型的VisitNoCache(),也基类中直接调用VisitCallSiteMain()


//// CallSiteRuntimeResolver
// 访问Root生命周期方法
protected override object VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
=> VisitCache(singletonCallSite, context, context.Scope.Engine.Root, RuntimeResolverLock.Root);
// 访问Scoped生命周期方法
protected override object VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
{
// 如果当前容器为根容器,则将其锁转换为Root,否则为Scope
var requiredScope = context.Scope == context.Scope.Engine.Root ?
RuntimeResolverLock.Root :
RuntimeResolverLock.Scope;
return VisitCache(singletonCallSite, context, context.Scope, requiredScope);
}
// 访问transient生命周期方法
protected override object VisitDisposeCache(ServiceCallSite transientCallSite, RuntimeResolverContext context)
=> context.Scope.CaptureDisposable(VisitCallSiteMain(transientCallSite, context)); //// CallSiteVisitor
// 无缓存
protected virtual TResult VisitNoCache(ServiceCallSite callSite, TArgument argument)
=> VisitCallSiteMain(callSite, argument);
**VisitCache()**这个方法是使用指定的容器进行实例化并缓存服务实例对象,在下面代码中可以看到,代码中根据**RuntimeResolverContext**实例的枚举值与第四个参数进行,如果不相同,则进行加锁。然后进行获取实例服务对象,如果已缓存则直接获取,没有缓存则调用**VisitCallSiteMain()**获取实例并缓存
private object VisitCache(ServiceCallSite scopedCallSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
{
bool lockTaken = false;
// 获取容器中的缓存服务实例属性
var resolvedServices = serviceProviderEngine.ResolvedServices;
if ((context.AcquiredLocks & lockType) == 0)
// 如果当前枚举值与RuntimeResolverContext的枚举值不相同,则加锁
Monitor.Enter(resolvedServices, ref lockTaken);
try
{
// 如果当前数据并未在缓存之中,则实例化此对象并将其缓存至集合中
if (!resolvedServices.TryGetValue(scopedCallSite.Cache.Key, out var resolved))
{
// 获取实例对象
resolved = VisitCallSiteMain(scopedCallSite, new RuntimeResolverContext
{
Scope = serviceProviderEngine,
AcquiredLocks = context.AcquiredLocks | lockType
});
// 将当前对象尝试加入到容器的_disposables集合
serviceProviderEngine.CaptureDisposable(resolved);
// 缓存实例对象
resolvedServices.Add(scopedCallSite.Cache.Key, resolved);
}
return resolved;
}
finally
{
if (lockTaken)
Monitor.Exit(resolvedServices);
}
}
**VisitCallSiteMain()**内调用的所有方法都在`CallSiteRuntimeResolver`类进行了重写,下面看看`CallSiteRuntimeResolve`类中的这些方法
  • VisitFactory

    VisitFactory()中直接调用了FactoryCallSite实例对象的工厂方法获取实例

  • VisitIEnumerable

    VisitIEnumerable()中实例了IEnumerableCallSiteServiceCallSites集合的所有对象,并组装到一个数组进行返回

  • ConstructorCallSite

    VisitConstructor()中使用反射方法实例化对象,并且如果构造函数不为空则获取所有参数的实例对象

  • ConstantCallSite

    VisitConstant()中直接返回了ConstantCallSite中的对象

  • VisitServiceProvider

    VisitServiceProvider()直接返回了RuntimeResolverContext封装的容器

  • VisitServiceScopeFactory

    VisitServiceScopeFactory()中则直接返回了容器实例中引擎对象(ServiceProviderEngine)

//      FactoryCallSite
protected override object VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
// 调用工厂方法进行实例化
=> factoryCallSite.Factory(context.Scope); // IEnumerableCallSite
protected override object VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
{
var array = Array.CreateInstance(
enumerableCallSite.ItemType,
enumerableCallSite.ServiceCallSites.Length);
for (var index = 0; index < enumerableCallSite.ServiceCallSites.Length; index++)
{
// 实例化IEnumerableCallSite.ServiceCallSites中所有的服务实例对象并赋值到数组中
var value = VisitCallSite(enumerableCallSite.ServiceCallSites[index], context);
array.SetValue(value, index);
}
return array;
} // ConstructorCallSite
protected override object VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
{
object[] parameterValues;
if (constructorCallSite.ParameterCallSites.Length == 0)
parameterValues = Array.Empty<object>();
else
{
// 如果当前构造器参数不为空,则实例化每一个参数的实例对象
parameterValues = new object[constructorCallSite.ParameterCallSites.Length];
for (var index = 0; index < parameterValues.Length; index++)
parameterValues[index] = VisitCallSite(constructorCallSite.ParameterCallSites[index], context);
}
try
{
// 根据参数对象进行实例化对象并返回
return constructorCallSite.ConstructorInfo.Invoke(parameterValues);
}
catch (Exception ex) when (ex.InnerException != null)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
// The above line will always throw, but the compiler requires we throw explicitly.
throw;
}
} // ConstantCallSite
protected override object VisitConstant(ConstantCallSite constantCallSite, RuntimeResolverContext context)
// 直接返回ConstantCallSite的值
=> constantCallSite.DefaultValue; // ServiceProviderCallSite
protected override object VisitServiceProvider(ServiceProviderCallSite serviceProviderCallSite, RuntimeResolverContext context)
// 直接返回RuntimeResolverContext封装的容器
=> context.Scope; // ServiceScopeFactoryCallSite
protected override object VisitServiceScopeFactory(ServiceScopeFactoryCallSite serviceScopeFactoryCallSite, RuntimeResolverContext context)
// 直接返回容器内的ServiceProviderEngine
=> context.Scope.Engine;
在`CallSiteRuntimeResolver`中还有叫做**Resolve()**,这个方法则是外部调用的,这个方法是由一个`ServiceCallSite`对象和一个容器对象`ServiceProviderEngineScope`,然后直接调用**VisitCallSite()**进行方法,可以看到调用此方法时**AcquiredLocks**属性并未赋值.
public object Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
{
return VisitCallSite(callSite, new RuntimeResolverContext
{
Scope = scope
});
}

Core官方DI解析(4)--CallSiteRuntimeResolver的更多相关文章

  1. Core官方DI解析(3)-ServiceCallSite.md

    上一篇说过在整个DI框架中IServiceProviderEngine是核心,但是如果直接看IServiceProviderEngine派生类其实看不出也没什么东西,因为这个类型其实都是调用的其它对象 ...

  2. Core官方DI解析(5)-ServiceProviderEngine

    最后来看看前面一直说的Engine(工作引擎),工作引擎接口是IServiceProviderEngine在ServiceProvider的构造函数中看到了根据指定的Mode创建了不同的实现类,下面先 ...

  3. Core官方DI解析(2)-ServiceProvider

    ServiceProvider ServiceProvider是我们用来获取服务实例对象的类型,它也是一个特别简单的类型,因为这个类型本身并没有做什么,其实以一种代理模式,其核心功能全部都在IServ ...

  4. Core官方DI剖析(1)--ServiceProvider类和ServiceCollection类

    前段时间看了蒋老师的Core文章,对于DI那一块感觉挺有意思,然后就看了一下Core官方DI的源码,这也算是第一个看得懂大部分源码的框架,虽然官方DI相对来说特别简单, 官方DI相对于其它框架(例如 ...

  5. abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析

    老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...

  6. Asp.Net Core中DI的知识总结

    在asp.net core中DI的概念是由这几部分组成的: IServiceCollection,保存IServiceDescriptor实例的列表 IServiceProvider,只有一个方法Ge ...

  7. asp.net core的DI框架思考以及服务实例的获取方式总结

    转载请注明出处: https://home.cnblogs.com/u/zhiyong-ITNote/ 整个asp.net core管道从WebHostBuilder到WebHost到后续请求的类中, ...

  8. 实战Asp.Net Core:DI生命周期

    title: 实战Asp.Net Core:DI生命周期 date: 2018-11-30 21:54:52 --- 1.前言 Asp.Net Core 默认支持 DI(依赖注入) 软件设计模式,那使 ...

  9. 阅读DMA Controller Core 官方手册

    阅读DMA Controller Core 官方手册 DMA控制器框架图 怎样去设定一个DMA控制器 实例化DMA控制器 参数配置界面如下图所示: 对于width of the DMA length ...

随机推荐

  1. 震惊!计算机连0.3+0.6都算不对?浅谈IEEE754浮点数算数标准

    >>> 0.3+0.6 0.8999999999999999 >>> 1-0.9 0.09999999999999998 >>> 0.1+0.1+ ...

  2. 距离度量以及python实现(一)

    1. 欧氏距离(Euclidean Distance)        欧氏距离是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式. (1)二维平面上两点a(x1,y1)与b(x2,y2)间 ...

  3. 架构师入门:Spring Cloud系列,Hystrix与Eureka的整合

    和Ribbon等组件一样,在项目中,Hystrix一般不会单独出现,而是会和Eureka等组件配套出现.在Hystrix和Eureka整合后的框架里,一般会用到Hystrix的断路器以及合并请求等特性 ...

  4. Elasticsearch Index模块

    1.  Index Setting(索引设置) 每个索引都可以设置索引级别.可选值有: static  :只能在索引创建的时候,或者在一个关闭的索引上设置 dynamic:可以动态设置 1.1.  S ...

  5. Android项目目录结构模板以及简单说明【简单版】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 开发Android项目的时候,一般都是一边开发一边根据需求创建目录(包.module),那么我呢就根据以往的项目经验,整理出一个比较 ...

  6. 高效并发unsafe-星耀

    定义 Unsafe类是在sun.misc包下,不属于Java标准.但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty.Cassandra.Hado ...

  7. java~lombok里的Builder注解

    lombok注解在java进行编译时进行代码的构建,对于java对象的创建工作它可以更优雅,不需要写多余的重复的代码,这对于JAVA开发人员是很重要的,在出现lombok之后,对象的创建工作更提供Bu ...

  8. OpenCV各版本差异与演化,从1.x到4.0

    博客:blog.shinelee.me | 博客园 | CSDN 写在前面 最近因项目需要,得把OpenCV捡起来,登录OpenCV官网,竟然发现release了4.0.0-beata版本,所以借此机 ...

  9. Python:bs4的使用

    概述 bs4 全名 BeautifulSoup,是编写 python 爬虫常用库之一,主要用来解析 html 标签. 一.初始化 from bs4 import BeautifulSoup soup ...

  10. Flutter 即学即用系列博客——10 混淆

    前言 之前的博客我们都是在 debug 的模式下进行开发的. 实际发布到市场或者给到用户的都是 release 包. 而对于 Android 来说,release 包一个重要的步骤就是混淆. Andr ...