Orchard.Cache讲解
CacheModule是Orchard注入缓存的一个模块,所以这我们就来看一下CacheModule有什么东西
1 public class CacheModule : Module { 2 protected override void Load(ContainerBuilder builder) { 3 builder.RegisterType<DefaultCacheManager>() 4 .As<ICacheManager>() 5 .InstancePerDependency(); 6 } 7 8 protected override void AttachToComponentRegistration(Autofac.Core.IComponentRegistry componentRegistry, Autofac.Core.IComponentRegistration registration) { 9 var needsCacheManager = registration.Activator.LimitType 10 .GetConstructors() 11 .Any(x => x.GetParameters() 12 .Any(xx => xx.ParameterType == typeof(ICacheManager))); 13 14 if (needsCacheManager) { 15 registration.Preparing += (sender, e) => { 16 var parameter = new TypedParameter( 17 typeof(ICacheManager), 18 e.Context.Resolve<ICacheManager>(new TypedParameter(typeof(Type), registration.Activator.LimitType))); 19 e.Parameters = e.Parameters.Concat(new[] { parameter }); 20 }; 21 } 22 } 23 }
这里先解释下这边的注入实现的代码
builder.RegisterType<DefaultCacheManager>() .As<ICacheManager>() .InstancePerDependency();
将DefaultCacheManager注册为ICacheManager的每个依赖的实现类
接下来 我们在看一下重写AttachToComponentRegistration方法的实现内容
如果有一个接收ICacheManager类型为参数的构造函数,那么Autofac容器在解析这个类对象生成之前,会按照这里面的实现方式解析出一个ICacheManager接口的实现类。其中ICacheManager实现类的
构造函数参数类型为Type的值为具有ICacheManager接口构造函数的类型【这个有点绕】
DefaultCacheManager是与具有ICacheManager参数构造函数的类型相关的。这样做法是为了让每一个调用ICacheManager的类都有自己的缓存实例,彼此之间不共享。
接着,我们看一下缓存接口ICacheManger
1 public interface ICacheManager { 2 TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire); 3 ICache<TKey, TResult> GetCache<TKey, TResult>(); 4 }
一个是用来获取ICached对象,一个是用来获取缓存结果值
下一步,我们看下它的实现类
1 public class DefaultCacheManager : ICacheManager { 2 private readonly Type _component; 3 private readonly ICacheHolder _cacheHolder; 4 5 /// <summary> 6 /// Constructs a new cache manager for a given component type and with a specific cache holder implementation. 7 /// </summary> 8 /// <param name="component">The component to which the cache applies (context).</param> 9 /// <param name="cacheHolder">The cache holder that contains the entities cached.</param> 10 public DefaultCacheManager(Type component, ICacheHolder cacheHolder) { 11 _component = component; 12 _cacheHolder = cacheHolder; 13 } 14 15 /// <summary> 16 /// Gets a cache entry from the cache holder. 17 /// </summary> 18 /// <typeparam name="TKey">The type of the key to be used to fetch the cache entry.</typeparam> 19 /// <typeparam name="TResult">The type of the entry to be obtained from the cache.</typeparam> 20 /// <returns>The entry from the cache.</returns> 21 public ICache<TKey, TResult> GetCache<TKey, TResult>() { 22 return _cacheHolder.GetCache<TKey, TResult>(_component); 23 } 24 25 public TResult Get<TKey, TResult>(TKey key, Func<AcquireContext<TKey>, TResult> acquire) { 26 return GetCache<TKey, TResult>().Get(key, acquire); 27 } 28 }
我们看到构造函数有一个ICacheHolder,而这个才是DefaultCahceManager缓存接口实现真正的执行者。
那我们就来看下这个ICacheHolder接口
1 public interface ICacheHolder : ISingletonDependency { 2 ICache<TKey, TResult> GetCache<TKey, TResult>(Type component); 3 }
public class DefaultCacheHolder : ICacheHolder { private readonly ICacheContextAccessor _cacheContextAccessor; private readonly ConcurrentDictionary<CacheKey, object> _caches = new ConcurrentDictionary<CacheKey, object>(); public DefaultCacheHolder(ICacheContextAccessor cacheContextAccessor) { _cacheContextAccessor = cacheContextAccessor; } class CacheKey : Tuple<Type, Type, Type> { public CacheKey(Type component, Type key, Type result) : base(component, key, result) { } } /// <summary> /// Gets a Cache entry from the cache. If none is found, an empty one is created and returned. /// </summary> /// <typeparam name="TKey">The type of the key within the component.</typeparam> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="component">The component context.</param> /// <returns>An entry from the cache, or a new, empty one, if none is found.</returns> 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; } }
DefaultCacheHolder使用线程安全的ConcurrentDictionary<CacheKey,object>型字典来保存缓存,这里就暂时称为
类型缓存字典,这个字典缓存的不是实际存储的值,而是一个类型为Cache<Tkey,TResult>这样的一个对象类型。
CacheKey是这个缓存字典的Key,而Cache是缓存字典的值。所以接下来我们来看下这个Cahce的结构
1 public class Cache<TKey, TResult> : ICache<TKey, TResult> { 2 private readonly ICacheContextAccessor _cacheContextAccessor; 3 private readonly ConcurrentDictionary<TKey, CacheEntry> _entries; 4 5 public Cache(ICacheContextAccessor cacheContextAccessor) { 6 _cacheContextAccessor = cacheContextAccessor; 7 _entries = new ConcurrentDictionary<TKey, CacheEntry>(); 8 } 9 10 public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) { 11 var entry = _entries.AddOrUpdate(key, 12 // "Add" lambda 13 k => AddEntry(k, acquire), 14 // "Update" lambda 15 (k, currentEntry) => UpdateEntry(currentEntry, k, acquire)); 16 17 return entry.Result; 18 } 19 20 private CacheEntry AddEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) { 21 var entry = CreateEntry(k, acquire); 22 PropagateTokens(entry); 23 return entry; 24 } 25 26 private CacheEntry UpdateEntry(CacheEntry currentEntry, TKey k, Func<AcquireContext<TKey>, TResult> acquire) { 27 var entry = (currentEntry.Tokens.Any(t => t != null && !t.IsCurrent)) ? CreateEntry(k, acquire) : currentEntry; 28 PropagateTokens(entry); 29 return entry; 30 } 31 32 private void PropagateTokens(CacheEntry entry) { 33 // Bubble up volatile tokens to parent context 34 if (_cacheContextAccessor.Current != null) { 35 foreach (var token in entry.Tokens) 36 _cacheContextAccessor.Current.Monitor(token); 37 } 38 } 39 40 41 private CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) { 42 var entry = new CacheEntry(); 43 var context = new AcquireContext<TKey>(k, entry.AddToken); 44 45 IAcquireContext parentContext = null; 46 try { 47 // Push context 48 parentContext = _cacheContextAccessor.Current; 49 _cacheContextAccessor.Current = context; 50 51 entry.Result = acquire(context); 52 } 53 finally { 54 // Pop context 55 _cacheContextAccessor.Current = parentContext; 56 } 57 entry.CompactTokens(); 58 return entry; 59 } 60 61 private class CacheEntry { 62 private IList<IVolatileToken> _tokens; 63 public TResult Result { get; set; } 64 65 public IEnumerable<IVolatileToken> Tokens { 66 get { 67 return _tokens ?? Enumerable.Empty<IVolatileToken>(); 68 } 69 } 70 71 public void AddToken(IVolatileToken volatileToken) { 72 if (_tokens == null) { 73 _tokens = new List<IVolatileToken>(); 74 } 75 76 _tokens.Add(volatileToken); 77 } 78 79 public void CompactTokens() { 80 if (_tokens != null) 81 _tokens = _tokens.Distinct().ToArray(); 82 } 83 } 84 }
这里面有个
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
这个就是缓存条目对象的字典。我们先看下CacheEntry这个对象的结构
1 private class CacheEntry { 2 private IList<IVolatileToken> _tokens; 3 public TResult Result { get; set; } 4 5 public IEnumerable<IVolatileToken> Tokens { 6 get { 7 return _tokens ?? Enumerable.Empty<IVolatileToken>(); 8 } 9 } 10 11 public void AddToken(IVolatileToken volatileToken) { 12 if (_tokens == null) { 13 _tokens = new List<IVolatileToken>(); 14 } 15 16 _tokens.Add(volatileToken); 17 } 18 19 public void CompactTokens() { 20 if (_tokens != null) 21 _tokens = _tokens.Distinct().ToArray(); 22 } 23 }
这个缓存条目,是一个内部类。它包含两个属性:一个是缓存的结果TResult,一个是挥发令牌集合IEnumerable<IVolatileToken>
缓存条目的创建
1 private CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) { 2 var entry = new CacheEntry(); 3 var context = new AcquireContext<TKey>(k, entry.AddToken); 4 5 IAcquireContext parentContext = null; 6 try { 7 // Push context 8 parentContext = _cacheContextAccessor.Current; 9 _cacheContextAccessor.Current = context; 10 11 entry.Result = acquire(context); 12 } 13 finally { 14 // Pop context 15 _cacheContextAccessor.Current = parentContext; 16 } 17 entry.CompactTokens(); 18 return entry; 19 }
这里,我们先看下_cacheContextAccessor这个是什么东西
1 public class DefaultCacheContextAccessor : ICacheContextAccessor { 2 [ThreadStatic] 3 private static IAcquireContext _threadInstance; 4 5 public static IAcquireContext ThreadInstance { 6 get { return _threadInstance; } 7 set { _threadInstance = value; } 8 } 9 10 public IAcquireContext Current { 11 get { return ThreadInstance; } 12 set { ThreadInstance = value; } 13 } 14 }
我们看到IAcquireContext有个特性:[ThreadStatic],每一个线程独立存储。
接着我们回到缓存条目创建
var entry = new CacheEntry();
var context = new AcquireContext<TKey>(k, entry.AddToken);
IAcquireContext parentContext = null;
try {
// 将context放入栈中
parentContext = _cacheContextAccessor.Current;
_cacheContextAccessor.Current = context;
entry.Result = acquire(context);//获取缓存
}
finally {
// 将context从栈中取出,还原
_cacheContextAccessor.Current = parentContext;
}
entry.CompactTokens();//去重
了解了缓存条目的创建方式,接着看下缓存的添加方式
private CacheEntry AddEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) { var entry = CreateEntry(k, acquire); PropagateTokens(entry); return entry; }
//传送Tokens
private void PropagateTokens(CacheEntry entry) { // Bubble up volatile tokens to parent context if (_cacheContextAccessor.Current != null) { foreach (var token in entry.Tokens) _cacheContextAccessor.Current.Monitor(token); } }
更新缓存
1 private CacheEntry UpdateEntry(CacheEntry currentEntry, TKey k, Func<AcquireContext<TKey>, TResult> acquire) { 2 var entry = (currentEntry.Tokens.Any(t => t != null && !t.IsCurrent)) ? CreateEntry(k, acquire) : currentEntry; 3 PropagateTokens(entry); 4 return entry; 5 }
获取缓存
1 public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) { 2 var entry = _entries.AddOrUpdate(key, 3 // "Add" lambda 4 k => AddEntry(k, acquire), 5 // "Update" lambda 6 (k, currentEntry) => UpdateEntry(currentEntry, k, acquire)); 7 8 return entry.Result; 9 }
DefaultCacheHolder提供了一系列缓存策略的扩展
在Cache命名空间下有:
IParallelCacheContext
IAsyncTokenProvider
IAcquireContext
ISignals : IVolatileProvider
等一些列接口