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

等一些列接口

下一篇:Orchard.Cahce缓存过期机制案例分析

posted @ 2016-12-15 23:55  AntColony  阅读(452)  评论(0编辑  收藏  举报