- A+
所属分类:.NET技术
使用IOC容器最重要的两个步骤就是注入服务和从容器内获取服务实例。上一节聊的ServiceDescriptor其实就可以看成注入服务的步骤,这一节初步聊一聊获取服务实例的相关源码。
- GetService
GetService 方法是获取服务实例的入口,位于 ServiceProvider 这个类中
public object? GetService(Type serviceType) => GetService(serviceType, Root); internal object? GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope) { ... //如果有 realizedService 里有 ,获取,没有 就添加(serviceType 为key) GetOrAdd(key,valueFactory) 根据key生成value Func<ServiceProviderEngineScope, object?> realizedService = _realizedServices.GetOrAdd(serviceType, _createServiceAccessor); //检验能否解析 .... //获取服务实例 此处的核心 是 CallSiteRuntimeResolver 类(负责根据 scope 进行服务解析) var result = realizedService.Invoke(serviceProviderEngineScope); ... return result; }
从上面的代码可以看出,主要经历了两步,第一步根据 _createServiceAccessor
获取一个泛型委托,第二步使用泛型委托生成服务实例。
- _createServiceAccssor
_createServiceAccssor 是获取
// 定义 private readonly Func<Type, Func<ServiceProviderEngineScope, object?>> _createServiceAccessor; //初始化是在 ServiceProvider 的构造函数中 _createServiceAccessor = CreateServiceAccessor; // CreateServiceAccessor 方法 private Func<ServiceProviderEngineScope, object?> CreateServiceAccessor(Type serviceType) { //通过 服务类型 获取 callSite,CallSite 包含了如何生成服务实例的相关信息, 比如服务实例的生命周期 ServiceCallSite? callSite = CallSiteFactory.GetCallSite(serviceType, new CallSiteChain()); if (callSite != null) { ... // Optimize singleton case 针对单例的优化 if (callSite.Cache.Location == CallSiteResultCacheLocation.Root) { //直接解析,如果callSite 里有,就直接返回 callSite 里存的值 object? value = CallSiteRuntimeResolver.Instance.Resolve(callSite, Root); //以委托形式存下来 return scope => value; } //生成一个 可以通过 callSite 生成实例的委托 return _engine.RealizeService(callSite); } return _ => null; } // 返回一个委托 Func<ServiceProviderEngineScope, object?> // 该委托用途是生成 callSite 对应的servieType实例 public override Func<ServiceProviderEngineScope, object?> RealizeService(ServiceCallSite callSite) { int callCount = 0; return scope => { var result = CallSiteRuntimeResolver.Instance.Resolve(callSite, scope); } }
首先通过CallSiteFactory获取一个一个callSite(在CallSiteFactory
类中),可以先记住callSite作用是缓存和生成服务实例的细节,比如服务之间的依赖关系,如何创建实例的依赖。接下来则是根据服务的作用于范围,对单例做了优化,主要就是加了缓存(这个也是由callSite实现的),不用每次都去解析一次。如果不是单例,就需要结合callSite和_engine(scope相关)来获取服务了。但是从代码可以看出来无论是 Singleton 还是其他生命周期,最终调用的还是CallSiteRuntimeResolver.Instance.Resolve
这个方法。
public object? Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) { // Fast path to avoid virtual calls if we already have the cached value in the root scope // 如果在 root scope 范围里已经有缓存了,直接返回,也就是对单例的优化,缓存 if (scope.IsRootScope && callSite.Value is object cached) { return cached; } //调用 VisitCallSite 进行解析 return VisitCallSite(callSite, new RuntimeResolverContext { Scope = scope }); }
因为对单例做了缓存,所以如果已经解析过了,就会直接返回缓存里的值,否则就调用VisitCallSite
进行解析。
VisitCallSite
这个方法打算放到下节,对这部分感兴趣的也可以自行先去看一看CallSiteRuntimeResolver
这个类。
- 根据泛型委托生成服务实例,这个就是简单的调用委托
var result = realizedService.Invoke(serviceProviderEngineScope);
======================================
补充
- ServiceCallSite, 可以看到里面有一个 Value,那个就是缓存的单例的值
internal abstract class ServiceCallSite { // 构建方式 实例,工厂,构造器 public abstract CallSiteKind Kind { get; } //生命周期 和 cacheKey public ResultCache Cache { get; } //Singleton存放点 public object? Value { get; set; } }