[转载].Net通用基础框架(.Net Common Infrastructure)-缓存

[转载].Net通用基础框架(.Net Common Infrastructure)-缓存 – 张艺聍 – 博客园.

缓存可以提高网站性能,减轻数据库压力。网站中常用的缓存分为业务数据缓存和页面文件缓存两类,其中业务数据缓存常用AspnetCache,Memcached等,而页面文件缓存常用Squid和Nginx,今天 介绍的内容是业务数据缓存。

  • Common.Cache类图

  • 缓存接口ICache:使用Add方法时,如果key存在,则返回false。使用Set方法时,key不存在则添加,否则更新。
using System;
using System.Collections.Generic;

namespace Common.Cache
{
/// <summary>
/// 缓存
/// </summary>
public interface ICache
{
/// <summary>
/// 增加
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>结果</returns>
bool Add<T>(string key, T value);

/// <summary>
/// 增加
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="duration">持续时间</param>
/// <returns>结果</returns>
bool Add<T>(string key, T value, TimeSpan duration);

/// <summary>
/// 清除
/// </summary>
void Clear();

/// <summary>
/// 获取
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <returns>值</returns>
T Get<T>(string key);

/// <summary>
/// 多线程获取
/// </summary>
/// <param name="keys">键集合</param>
/// <returns>值集合</returns>
IDictionary<string, object> MultiGet(IList<string> keys);

/// <summary>
/// 移除
/// </summary>
/// <param name="key">键</param>
void Remove(string key);

/// <summary>
/// 设置
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <returns>结果</returns>
bool Set<T>(string key, T value);

/// <summary>
/// 设置
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="key">键</param>
/// <param name="value">值</param>
/// <param name="duration">持续时间</param>
/// <returns>结果</returns>
bool Set<T>(string key, T value, TimeSpan duration);
}
}

缓存基类

using System;
using System.Collections.Generic;

namespace Common.Cache
{
/// <summary>
/// 缓存基类
/// </summary>
public abstract class CacheBase : ICache
{
private TimeSpan maxDuration = TimeSpan.FromDays(15);

/// <summary>
/// 最长持续时间
/// </summary>
public TimeSpan MaxDuration
{
get
{
return this.maxDuration;
}
set
{
this.maxDuration = value;
}
}

/// <summary>
/// 前缀
/// </summary>
public string Prefix
{
get;
set;
}

public bool Add<T>(string key, T value)
{
return this.Add<T>(key, value, this.MaxDuration);
}

public abstract bool Add<T>(string key, T value, TimeSpan duration);

public abstract void Clear();

public abstract T Get<T>(string key);

/// <summary>
/// 获取全名
/// </summary>
/// <param name="key">键</param>
/// <returns>全名</returns>
public virtual string GetFullName(string key)
{
string result = key;
if (!string.IsNullOrWhiteSpace(this.Prefix))
{
result = string.Format("{0}.{1}", this.Prefix, key);
}

return result;
}

public abstract IDictionary<string, object> MultiGet(IList<string> keys);

public abstract void Remove(string key);

public bool Set<T>(string key, T value)
{
return this.Set<T>(key, value, this.MaxDuration);
}

public abstract bool Set<T>(string key, T value, TimeSpan duration);
}
}

Aspnet缓存实现

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;

namespace Common.Cache
{
/// <summary>
/// Aspnet缓存
/// </summary>
public class AspnetCache : CacheBase
{
private System.Web.Caching.Cache cache = HttpRuntime.Cache;

/// <summary>
/// 构造函数
/// </summary>
public AspnetCache()
: this("Common.Cache")
{

}

/// <summary>
/// 构造函数
/// </summary>
/// <param name="prefix">前缀</param>
public AspnetCache(string prefix)
{
this.Prefix = prefix;
}

public override bool Add<T>(string key, T value, TimeSpan duration)
{
bool result = false;
if (value != null)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}
result = this.cache.Add(this.GetFullName(key), value, null, DateTime.Now.Add(duration), System.Web.Caching.Cache.NoSlidingExpiration, CacheItemPriority.Default, null) == null;
}

return result;
}

public override void Clear()
{
// 获取键集合
IList<string> keys = new List<string>();
IDictionaryEnumerator caches = this.cache.GetEnumerator();
while (caches.MoveNext())
{
string key = caches.Key.ToString();
if (key.StartsWith(this.Prefix))
{
keys.Add(key);
}
}
// 移除全部
foreach (string key in keys)
{
this.cache.Remove(key);
}
}

public override T Get<T>(string key)
{
T result = default(T);
object value = this.cache.Get(this.GetFullName(key));
if (value is T)
{
result = (T)value;
}

return result;
}

public override IDictionary<string, object> MultiGet(IList<string> keys)
{
IDictionary<string, object> result = new Dictionary<string, object>();
foreach (string key in keys)
{
result.Add(key, this.Get<object>(key));
}

return result;
}

public override void Remove(string key)
{
this.cache.Remove(this.GetFullName(key));
}

public override bool Set<T>(string key, T value, TimeSpan duration)
{
bool result = false;
if (value != null)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}
this.cache.Insert(this.GetFullName(key), value, null, DateTime.Now.Add(duration), System.Web.Caching.Cache.NoSlidingExpiration);
result = true;
}

return result;
}
}
}

&#91;/csharp&#93;

Memcached分布式缓存实现:EnyimMemcached客户端中实现了一致性哈希算法

&#91;csharp&#93;
using System;
using System.Collections.Generic;
using System.Linq;
using Enyim.Caching;
using Enyim.Caching.Memcached;

namespace Common.Cache
{
/// <summary>
/// Memcached缓存
/// </summary>
public class MemcachedCache : CacheBase
{
private static MemcachedClient memcached = new MemcachedClient();

public override bool Add<T>(string key, T value, TimeSpan duration)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}

return memcached.Store(StoreMode.Add, this.GetFullName(key), value, duration);
}

public override void Clear()
{
memcached.FlushAll();
}

public override T Get<T>(string key)
{
return memcached.Get<T>(this.GetFullName(key));
}

public override IDictionary<string, object> MultiGet(IList<string> keys)
{
IEnumerable<string> fullKeys = keys.Select<string, string>(k => this.GetFullName(k));

return memcached.Get(fullKeys);
}

public override void Remove(string key)
{
memcached.Remove(this.GetFullName(key));
}

public override bool Set<T>(string key, T value, TimeSpan duration)
{
if (duration <= TimeSpan.Zero)
{
duration = this.MaxDuration;
}

return memcached.Store(StoreMode.Set, this.GetFullName(key), value, duration);
}
}
}

&#91;/csharp&#93;

缓存结果通知:实现了Spring.Aop中的IMethodInterceptor接口,用Spring的表达式解析得出key的值,使用时在方法上打特性标签,如Common.Mom项目中用到的&#91;CacheResult(CacheName = "Aspnet", Key = "'Cmr.Dsr.GetSubscriber.' + #id", TimeToLive = "0:5:0")&#93;
&#91;csharp&#93;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using AopAlliance.Intercept;
using Spring.Caching;
using Spring.Context;
using Spring.Expressions;

namespace Common.Cache.Aspects
{
/// <summary>
/// 缓存结果通知
/// </summary>
public class CacheResultAdvice : IApplicationContextAware, IMethodInterceptor
{
private IDictionary<MethodInfo, CacheResultAttribute> cacheResults = new Dictionary<MethodInfo, CacheResultAttribute>();

public IApplicationContext ApplicationContext
{
get;
set;
}

/// <summary>
/// 获取缓存结果
/// </summary>
/// <param name="invocation">调用</param>
/// <returns>缓存结果</returns>
private CacheResultAttribute GetCacheResult(IMethodInvocation invocation)
{
CacheResultAttribute result = null;
MethodInfo method = invocation.Method;
if (this.cacheResults.ContainsKey(method))
{
result = this.cacheResults[method];
}
if (result == null)
{
object[] attributes = method.GetCustomAttributes(typeof(CacheResultAttribute), false);
if (attributes.Length > 0)
{
result = (CacheResultAttribute)attributes[0];
this.cacheResults[method] = result;
}
}

return result;
}

/// <summary>
/// 获取参数集合
/// </summary>
/// <param name="invocation">调用</param>
/// <returns>参数集合</returns>
private IDictionary GetParameters(IMethodInvocation invocation)
{
IDictionary result = new Hashtable();
MethodInfo method = invocation.Method;
object[] arguments = invocation.Arguments;
ParameterInfo[] parameters = method.GetParameters();
for (int i = 0; i < parameters.Length; i++)
{
ParameterInfo parameter = parameters&#91;i&#93;;
result&#91;parameter.Name&#93; = arguments&#91;i&#93;;
}

return result;
}

public object Invoke(IMethodInvocation invocation)
{
object result = null;
IDictionary parameters = this.GetParameters(invocation);
CacheResultAttribute cacheResult = this.GetCacheResult(invocation);
if (cacheResult != null && cacheResult.KeyExpression != null)
{
string key = cacheResult.KeyExpression.GetValue(null, parameters).ToString();
if (!string.IsNullOrEmpty(key))
{
ICache cache = this.ApplicationContext.GetObject(cacheResult.CacheName) as ICache;
if (cache != null)
{
result = cache.Get<object>(key);
if (result == null)
{
result = invocation.Proceed();
if (this.IsMatch(cacheResult.ConditionExpression, result, parameters))
{
cache.Set<object>(key, result, cacheResult.TimeToLiveTimeSpan);
}
}
}
}
}
if (result == null)
{
result = invocation.Proceed();
}

return result;
}

/// <summary>
/// 是否匹配
/// </summary>
/// <param name="expression">表达式</param>
/// <param name="context">上下文</param>
/// <param name="parameters">参数集合</param>
/// <returns>结果</returns>
private bool IsMatch(IExpression expression, object context, IDictionary parameters)
{
bool result = expression == null;
if (!result)
{
result = (bool)expression.GetValue(result, parameters);
}

return result;
}
}
}

测试时启动Common.Cache.ConsoleTest即可

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏