接着上面一节,这一节主要来看看 callSite 是如何生成的
CallSite
是通过 CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
生成的,CallSiteFactory
是在 ServiceProvider
里实例化的。代码如下
private readonly ConcurrentDictionary<ServiceCacheKey, ServiceCallSite> _callSiteCache
= new ConcurrentDictionary<ServiceCacheKey, ServiceCallSite>();
//从 _callSiteCache 查找,如果有直接返回,如果没有 调用 CreateCallSite() 方法创建
internal ServiceCallSite? GetCallSite(Type serviceType, CallSiteChain callSiteChain) =>
_callSiteCache.TryGetValue(
new ServiceCacheKey(serviceType, DefaultSlot), out ServiceCallSite? site)
? site :CreateCallSite(serviceType, callSiteChain);
从上述代码可以看出来接下来就是调用了 CreateCallSite
方法。
private ServiceCallSite? CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
{
...
// We need to lock the resolution process for a single service type at a time:
// Consider the following:
// C -> D -> A
// E -> D -> A
// 如上例,当 C,E 同时解析时,为了确保只会生成一个 D 对应的 CallSite,所以需要锁住
// 尝试从 _callSiteLocks 获取一个值,没有则添加,返回获取到或者添加的值
var callsiteLock = _callSiteLocks.GetOrAdd(serviceType, static _ => new object());
lock (callsiteLock)
{
//检查serviceType的循环依赖
callSiteChain.CheckCircularDependency(serviceType);
//根据 serviceType 创建 callSite
ServiceCallSite? callSite =
//如果 TryCreateExact 为空,那么就说明可能 是泛型,并且注册的时候使用的是 List<> 这种开放泛型,而不是List<int> 这种具体泛型
//所以需要尝试一下 TryCreateOpenGeneric
TryCreateExact(serviceType, callSiteChain)
??TryCreateOpenGeneric(serviceType, callSiteChain)
??TryCreateEnumerable(serviceType, callSiteChain);
return callSite;
}
}
这里根据 serviceType 的类型走了不同的分支
- TryCreateExact (精确匹配,serviceType是一个具体类型)
private ServiceCallSite? TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
{
//判断 服务类型是否在 _descriptorLookup(创建CallSiteFactory时由 ServiceDescriptor 集合 初始化) 里,就是看之前有没有注入过
if (_descriptorLookup.TryGetValue(serviceType, out ServiceDescriptorCacheItem descriptor)){
//因为一个 serviceType 可能会注册多个 ServiceDescriptor 此处取最新的(详情见上populate方法)
return TryCreateExact(descriptor.Last, serviceType, callSiteChain, DefaultSlot);
}
return null;
}
private ServiceCallSite? TryCreateExact(
ServiceDescriptor descriptor,
Type serviceType,
CallSiteChain callSiteChain,
int slot
)
{
// 精确匹配需要获取的类型(serviceType)和注入的类型(descriptor.serviceType)
if (serviceType == descriptor.ServiceType)
{
//用serviceType 和 slot 构建一个 ServiceCacheKey
ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot);
//如果有缓存,直接返回 这里并不能解决循环依赖问题,
//举例 A依赖B B依赖A 此时 A 还没有注入进去,所以这里不会获得A,依旧会继续构建,导致循环依赖
if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite))
{
return serviceCallSite;
}
ServiceCallSite callSite;
//使用 lifetime serviceType slot 构建一个 ResultCache
var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);
//如果有 实现实例
if (descriptor.ImplementationInstance != null)
{
//构建一个 ConstantCallSite 实例就是单例模式,不需要lifetime了
callSite = new ConstantCallSite(descriptor.ServiceType, descriptor.ImplementationInstance);
}
// 如果有 实现工厂
else if (descriptor.ImplementationFactory != null)
{
//构建一个 FactoryCallSite
callSite = new FactoryCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationFactory);
}
// 如果有实现类型
else if (descriptor.ImplementationType != null)
{
//构建一个 ConstructorCallSite
callSite = CreateConstructorCallSite(lifetime, descriptor.ServiceType, descriptor.ImplementationType, callSiteChain);
}
else
{
throw new InvalidOperationException(SR.InvalidServiceDescriptor);
}
// 保存 callSiteKey 和 callSite 到 _callSiteCache 里
return _callSiteCache[callSiteKey] = callSite;
}
return null;
}
这里根据注入时指定的实例生成方法生成对应的CallSite
, 其中 ConstantCallSite
只能用于Singleton类型的生命周期,剩下的 FactoryCallSite
和 CreateConstructorCallSite
用于所有生命周期。我们主要分析一下 CreateConstructorCallSite
方法。
private ServiceCallSite CreateConstructorCallSite(
ResultCache lifetime,// serviceType 生命周期相关
Type serviceType,// 服务类型
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementationType,// 实现类型
CallSiteChain callSiteChain)// 依赖链
{
try
{
// callSiteChain 里添加当前 服务类型 和实现类型
callSiteChain.Add(serviceType, implementationType);
// 获取实现类型的 public 构造器
ConstructorInfo[] constructors = implementationType.GetConstructors();
// 构造这个类新依赖的类型
ServiceCallSite[]? parameterCallSites = null;
// 没有 public 构造器,抛出异常
if (constructors.Length == 0)
{
throw new InvalidOperationException(SR.Format(SR.NoConstructorMatch, implementationType));
}
//如果只有一个构造器
else if (constructors.Length == 1)
{
ConstructorInfo constructor = constructors[0];
ParameterInfo[] parameters = constructor.GetParameters();
//无参构造器
if (parameters.Length == 0)
{
return new ConstructorCallSite(lifetime, serviceType, constructor);
}
//获取参数 CallSite 不允许有没有的CallSite 因为这是唯一一个构造器
parameterCallSites = CreateArgumentCallSites(
implementationType,
callSiteChain,
parameters,
throwIfCallSiteNotFound: true)!;
return new ConstructorCallSite(lifetime, serviceType, constructor, parameterCallSites);
}
//按照参数数量进行 构造器倒序排序,跟后面挑选bestConstructor有关
Array.Sort(constructors,
(a, b) => b.GetParameters().Length.CompareTo(a.GetParameters().Length));
ConstructorInfo? bestConstructor = null;
HashSet<Type>? bestConstructorParameterTypes = null;
for (int i = 0; i < constructors.Length; i++)
{
ParameterInfo[] parameters = constructors[i].GetParameters();
//允许有没有的CallSite 因为这不是唯一一个构造器
ServiceCallSite[]? currentParameterCallSites = CreateArgumentCallSites(
implementationType,
callSiteChain,
parameters,
throwIfCallSiteNotFound: false);
if (currentParameterCallSites != null)
{
//如果当前没有bestConstructor,这个就是bestConstructor啦
if (bestConstructor == null)
{
bestConstructor = constructors[i];
parameterCallSites = currentParameterCallSites;
}
//bestConsturtor 不为null, 之前已经找到了一个可以使用的构造器
else
{
// Since we're visiting constructors in decreasing order of number of parameters,
// we'll only see ambiguities or supersets once we've seen a 'bestConstructor'.
//如果bestConstructorParameterTypes为null,使用 bestConstructor 的参数填充 bestConstructorParameterTypes
if (bestConstructorParameterTypes == null)
{
bestConstructorParameterTypes = new HashSet<Type>();
foreach (ParameterInfo p in bestConstructor.GetParameters())
{
bestConstructorParameterTypes.Add(p.ParameterType);
}
}
//如果 bestConstruct 的参数不能完全包含其他构造器的参数,抛出异常
//因为是按照构造器参数数量降序排的,所以如果多参数构造器不能包含少参数构造器,就有问题
foreach (ParameterInfo p in parameters)
{
if (!bestConstructorParameterTypes.Contains(p.ParameterType))
{
// Ambiguous match exception
throw new InvalidOperationException(string.Join(
Environment.NewLine,
SR.Format(SR.AmbiguousConstructorException, implementationType),
bestConstructor,
constructors[i]));
}
}
}
}
}
//没有 构造器,抛异常
if (bestConstructor == null)
{
throw new InvalidOperationException(
SR.Format(SR.UnableToActivateTypeException, implementationType));
}
else
{
Debug.Assert(parameterCallSites != null);
return new ConstructorCallSite(lifetime, serviceType, bestConstructor, parameterCallSites);
}
}
finally
{
//从 链中移除当前 类型
//可能原因:
//例 : A 依赖 B、D ,B 依赖 C, D 依赖于B
//A 构建 D,D 构建 B ,B 构建C 如果不移除, 当 A 构建 B 的时候,会发现 CallSiteSite 里有 B 会循环依赖
//但理论上不会,因为后续构建B的时候是直接从_callSiteCache里取的(CreateArgumentCallSites的GetCallSite),应该不用重新构建
// 构建完的依赖从链中移除
callSiteChain.Remove(serviceType);
}
}
从上面的代码可以看出服务之间的依赖关系是由CreateArgumentCallSites
解决的
private ServiceCallSite[]? CreateArgumentCallSites(
Type implementationType, // 实现类型
CallSiteChain callSiteChain,// 依赖链
ParameterInfo[] parameters, // 构造器参数
bool throwIfCallSiteNotFound) // 找不到是否抛出异常
{
var parameterCallSites = new ServiceCallSite[parameters.Length];
for (int index = 0; index < parameters.Length; index++)
{
Type parameterType = parameters[index].ParameterType;
//获取 类型 对应的 CallSite 这里是递归调用
ServiceCallSite? callSite = GetCallSite(parameterType, callSiteChain);
//如果没有 且 该参数类型有默认值 构建 一个 ConstantCallSite
if (callSite == null && ParameterDefaultValue.TryGetDefaultValue(parameters[index], out object? defaultValue))
{
callSite = new ConstantCallSite(parameterType, defaultValue);
}
//解析不出来参数的CallSite 抛出异常
if (callSite == null)
{
if (throwIfCallSiteNotFound)
{
throw new InvalidOperationException(SR.Format(SR.CannotResolveService,
parameterType,
implementationType));
}
return null;
}
//所有参数对应的 callSite (数组下标关联)
parameterCallSites[index] = callSite;
}
return parameterCallSites;
}
- TryCreateOpenGeneric
//泛型的CallSite注册
private ServiceCallSite? TryCreateOpenGeneric(Type serviceType, CallSiteChain callSiteChain)
{
// List<> IsConstructedGenericType false
// List<int> IsConstructedGenericType true
// 所以传入的 serviceType 如果是 泛型,就必须是可以构建的 泛型List<int>, 而不是 List<>
// 所以第二个 条件是判断有没有 对应 构建泛型的 开放泛型 (List<int> 对应 List<>)
if (serviceType.IsConstructedGenericType
&& _descriptorLookup.TryGetValue(serviceType.GetGenericTypeDefinition(), out ServiceDescriptorCacheItem descriptor))
{
return TryCreateOpenGeneric(descriptor.Last, serviceType, callSiteChain, DefaultSlot, true);
}
return null;
}
private ServiceCallSite? TryCreateOpenGeneric(
ServiceDescriptor descriptor,
Type serviceType,
CallSiteChain callSiteChain,
int slot,
bool throwOnConstraintViolation)
{
if (serviceType.IsConstructedGenericType &&
serviceType.GetGenericTypeDefinition() == descriptor.ServiceType)
{
ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, slot);
// 先看看缓存里有没有
if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite))
{
return serviceCallSite;
}
Debug.Assert(descriptor.ImplementationType != null, "descriptor.ImplementationType != null");
var lifetime = new ResultCache(descriptor.Lifetime, serviceType, slot);
Type closedType;
try
{
//根据 serviceType 的 泛型参数 构建一个确定的类型 List<> 根据 int 构建 List<int>,这个就是 实现
closedType = descriptor.ImplementationType.MakeGenericType(serviceType.GenericTypeArguments);
}
catch (ArgumentException)
{
if (throwOnConstraintViolation)
{
throw;
}
return null;
}
//调用CreateConstructorCallSite 方法,这就跟 TryCreateExtra 一致了
return _callSiteCache[callSiteKey] = CreateConstructorCallSite(lifetime, serviceType, closedType, callSiteChain);
}
return null;
}
- TryCreateEnumerable
这个方法的主要用途是注入了多个接口的不同实现,可以通过GetService<IEnumberable<T>>()
以 IEnumberable 形式获取所有实现
private ServiceCallSite? TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
{
ServiceCacheKey callSiteKey = new ServiceCacheKey(serviceType, DefaultSlot);
//缓存命中,直接返回
if (_callSiteCache.TryGetValue(callSiteKey, out ServiceCallSite? serviceCallSite))
{
return serviceCallSite;
}
try
{
callSiteChain.Add(serviceType);
// 是否是 ConstructedGenericType,并且 GetGenericTypeDefinition 是 IEnumerable (IEnumerable<int> 这种)
if (serviceType.IsConstructedGenericType &&
serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
//获取泛型的具体类型,<> 里面的
Type itemType = serviceType.GenericTypeArguments[0];
CallSiteResultCacheLocation cacheLocation = CallSiteResultCacheLocation.Root;
var callSites = new List<ServiceCallSite>();
// If item type is not generic we can safely use descriptor cache
//如果 <> 里不是泛型 并且 _descriptorLookup 里有这种类型(populate 的时候遇到过)
if (!itemType.IsConstructedGenericType &&
_descriptorLookup.TryGetValue(itemType, out ServiceDescriptorCacheItem descriptors))
{
//遍历 descriptors 里所有 descriptor
for (int i = 0; i < descriptors.Count; i++)
{
ServiceDescriptor descriptor = descriptors[i];
// Last service should get slot
int slot = descriptors.Count - i - 1;
// There may not be any open generics here
// 生成每个 descriptor 对应的 callSite
ServiceCallSite? callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot);
Debug.Assert(callSite != null);
// GetCommonCacheLocation = Math.max(a,b) 根据 新的callSite 调整location
cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location);
callSites.Add(callSite);
}
}
else
{
int slot = 0;
// We are going in reverse so the last service in descriptor list gets slot 0
//如果没有,遍历 populate 时添加进来的所有 _descriptor
for (int i = _descriptors.Length - 1; i >= 0; i--)
{
ServiceDescriptor descriptor = _descriptors[i];
// 尝试根据 descriptor 和 itemType 生成 callSite , 但是不满足条件的不会生成
ServiceCallSite? callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ??
TryCreateOpenGeneric(descriptor, itemType, callSiteChain, slot, false);
if (callSite != null)
{
// 当前 descriptr 可以生成 itemType slot++ 越后添加的slot越小
slot++;
// 调整 cacheLocation
cacheLocation = GetCommonCacheLocation(cacheLocation, callSite.Cache.Location);
callSites.Add(callSite);
}
}
//callSites 翻转 最新的跑到最前面
callSites.Reverse();
}
ResultCache resultCache = ResultCache.None;
//生命周期为 scoped 或者 Singleton 时 ,搞一个resultCache
if (cacheLocation == CallSiteResultCacheLocation.Scope || cacheLocation == CallSiteResultCacheLocation.Root)
{
resultCache = new ResultCache(cacheLocation, callSiteKey);
}
// 放入缓存
return _callSiteCache[callSiteKey] = new IEnumerableCallSite(resultCache, itemType, callSites.ToArray());
}
return null;
}
finally
{
callSiteChain.Remove(serviceType);
}
}
以上就是本节的所有内容了,如有错误,请多指教。
下一节我打算看一看在获得 callSite 之后,是如何根据 callSite 来生成具体实例的相关源码,主要是在 CallSiteRuntimeResolver
类中,感兴趣的朋友可以先看一看。
补充
CallSite的实现类
- ServiceCallSite
internal abstract class ServiceCallSite
{
// 构建方式 实例,工厂,构造器
public abstract CallSiteKind Kind { get; }
//生命周期 和 cacheKey
public ResultCache Cache { get; }
//Singleton存放点
public object? Value { get; set; }
}
- ConstantCallSite
internal class ConstantCallSite : ServiceCallSite
{
internal object DefaultValue { get; }
public ConstantCallSite(Type serviceType, object defaultValue) : base(ResultCache.None)
{
if (serviceType == null)
{
throw new ArgumentNullException("serviceType");
}
this._serviceType = serviceType;
if (defaultValue != null && !serviceType.IsInstanceOfType(defaultValue))
{
throw new ArgumentException(Resources.FormatConstantCantBeConvertedToServiceType(defaultValue.GetType(), serviceType));
}
this.DefaultValue = defaultValue;
}
public override Type ImplementationType
{
get
{
object defaultValue = this.DefaultValue;
return ((defaultValue != null) ? defaultValue.GetType() : null) ?? this._serviceType;
}
}
public override CallSiteKind Kind { get; } = 2;
private readonly Type _serviceType;
}
}
- FactoryCallSite
internal class FactoryCallSite : ServiceCallSite
{
public Func<IServiceProvider, object> Factory { get; }
public FactoryCallSite(ResultCache cache, Type serviceType, Func<IServiceProvider, object> factory) : base(cache)
{
this.Factory = factory;
this.ServiceType = serviceType;
}
public override Type ServiceType { get; }
public override Type ImplementationType
{
get
{
return null;
}
}
public override CallSiteKind Kind { get; }
}
- IEnumerableCallSite
internal class IEnumerableCallSite : ServiceCallSite
{
internal Type ItemType { get; }
internal ServiceCallSite[] ServiceCallSites { get; }
public IEnumerableCallSite(ResultCache cache, Type itemType, ServiceCallSite[] serviceCallSites) : base(cache)
{
this.ItemType = itemType;
this.ServiceCallSites = serviceCallSites;
}
public override Type ImplementationType
{
get
{
return this.ItemType.MakeArrayType();
}
}
public override CallSiteKind Kind { get; } = 3;
}
}
- ConstructorCallSite
internal class ConstructorCallSite : ServiceCallSite
{
internal ConstructorInfo ConstructorInfo { get; }
internal ServiceCallSite[] ParameterCallSites { get; }
public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo constructorInfo) : this(cache, serviceType, constructorInfo, Array.Empty<ServiceCallSite>())
{
}
public ConstructorCallSite(ResultCache cache, Type serviceType, ConstructorInfo constructorInfo, ServiceCallSite[] parameterCallSites) : base(cache)
{
ServiceType = serviceType;
ConstructorInfo = constructorInfo;
ParameterCallSites = parameterCallSites;
}
public override Type ServiceType { get; }
public override Type ImplementationType => ConstructorInfo.DeclaringType;
public override CallSiteKind Kind { get; } = CallSiteKind.Constructor;
}
PS
关于CallSiteChain的作用,目前我也不是特别清楚,比如为什么要需要在处理callSiteChain 时为什么要在 finally 块里把 type 给 remove 掉。希望知道的大佬可以指导一下。
标签:core,serviceType,CallSite,--,callSiteChain,descriptor,ServiceCallSite,callSite,n From: https://www.cnblogs.com/ccwzl/p/17512513.html