概述
CacheModule也是一个Autofac模块。
一、CacheModule类
CacheModule将DefaultCacheManager注册为ICacheManager:
public class CacheModule : Module {
protected override void Load( ContainerBuilder builder) {
builder.RegisterType<DefaultCacheManager>()
.As< ICacheManager>()
.InstancePerDependency();
}
//...
}
如果类有一个接受ICacheManager型的参数的构造函数,Autofac容器在解析(Resolve)该类生成对象之前,会先解析一个ICacheManager型对象作为参数:
public class CacheModule : Module {
//...
protected override void AttachToComponentRegistration(Autofac.Core. IComponentRegistry componentRegistry, Autofac.Core.IComponentRegistration registration) {
var needsCacheManager = registration.Activator.LimitType
.GetConstructors()
.Any(x => x.GetParameters()
.Any(xx => xx.ParameterType == typeof(ICacheManager )));
if (needsCacheManager) {
registration.Preparing += (sender, e) => {
var parameter = new TypedParameter(
typeof(ICacheManager ),
e.Context.Resolve< ICacheManager>(new TypedParameter( typeof(Type ), registration.Activator.LimitType)));
e.Parameters = e.Parameters.Concat( new[] { parameter });
};
}
}
}
Cache Manager是与类型相关的,这实际上是CacheModule存在的意义所在。比如Orchard.Environment.DefaultOrchardHost和其他类型不会共享同一个DefaultCacheManager对象。
二、DefaultCacheManager:ICacheManager类
DefaultCacheManager类公开了两个方法:
public ICache <TKey, TResult> GetCache<TKey, TResult>() {
return _cacheHolder.GetCache<TKey, TResult>(_component);
}
public TResult Get<TKey, TResult>(TKey key, Func< AcquireContext<TKey>, TResult> acquire) {
return GetCache<TKey, TResult>().Get(key, acquire);
}
第 一个方法可以获取类型相关的ICache<TKey,TResult>(Cache<TKey,TResult>)对象集合;第 二个方法通过Key值获取具体的某一个Cache Result,即实际的缓存值。Cache<TKey,TResult>会在下面介绍。
不难看出,DefaultCacheManager是对ICacheHolder的简单封装,就算没有DefaultCacheManager类,也可以不怎么方便地使用缓存机制,因为实际的缓存存取是交给ICacheHolder来处理的,默认使用的是DefaultCacheHolder,这是一个应用程序域级的单例。
三、DefaultCacheHolder:ICacheHolder类
绝大多数的缓存机制都是采用字典的形式,DefaultCacheHolder中使用线程安全的ConcurrentDictionary<CacheKey, object>型字典来保存缓存,这里称为类型缓存字典,注意该字典中并不存储实际的缓存值。为了方便,在这里我们把CacheKey称为类型缓存字典Key;object称为类型缓存字典Value, 实际类型为泛型Cache<TKey,TResult>:ICache<TKey,TResult>的封闭类型。 Cache<TKey,Result>内部也有一个字典,类型为ConcurrentDictionary<TKey, CacheEntry>。在这里,TKey称为缓存字典Key,CacheEntry称为缓存字典Value。
CacheEntry有一个类型为TResult名为Result的属性,这里称为缓存Result,这才是实际的缓存值。
在分析源码的时候要特别区分这些我们约定的概念:
1、类型缓存字典、类型缓存字典Key、类型缓存字典Value
2、缓存字典、缓存字典Key、缓存字典Value和缓存Result。
在使用缓存时,我们是通过"缓存字典Key"来获取一个"缓存Result"。
DefaultCacheHolder仅公开了一个GetCache方法:
public ICache<TKey, TResult> GetCache<TKey, TResult>(Type component) {
var cacheKey = new CacheKey(component, typeof(TKey), typeof (TResult));
var result = _caches.GetOrAdd(cacheKey, k => new Cache<TKey, TResult>(_cacheContextAccessor));
return (Cache <TKey, TResult>)result;
}
方法首先使用两个泛型参数的类型加上一个方法参数(Type型),可以构成一个CacheKey。CacheKey是一个三元组:
class CacheKey : Tuple<Type, Type , Type> {
public CacheKey(Type component, Type key, Type result)
: base(component, key, result) {
}
}
然后从类型缓存字典中获取一个Cache<TKey, TResult>:ICache<TKey,TResult>对象。这时可以认为获取了一个类型相关的缓存字典。调用Cache<TKey, TResult>对象Get方法获取实际的缓存值。
DefaultCacheHolder 采用延迟缓存机制,在第一次从缓存中获取对象时才会去构建对象;提供可扩展的缓存到期、更新策略,比如使用Orchard.Services.Clock 类配合可以让缓存在某个具体的时间到期或一定时间间隔到期。缓存过期并不表示它在内存中被立即销毁,而是会在下一次尝试获取缓存的时候重新生成缓存。
相关类型(皆在Orchard.Caching命名空间下):
DefaultCacheManager : ICacheManager
DefaultCacheHolder : ICacheHolder
DefaultCacheContextAccessor : ICacheContextAccessor
DefaultParallelCacheContext : IParallelCacheContext
DefaultAsyncTokenProvider : IAsyncTokenProvider
AcquireContext<TKey>:IAcquireContext
SimpleAcquireContext : IAcquireContext
Signals : ISignals : IVolatileProvider : ISingletonDependency
Signals.Token : IVolatileToken(Private nested class)
Cache<TKey, TResult> : ICache<TKey, TResult>
CacheEntry(Private class)
Weak<T>
参考资料:
Autofac:Structuring With Modules
http://skywalkersoftwaredevelopment.net/orchard-development/api/autofac-module