工作中需要用到内存缓存,最开始打算用个的是.net自带的MemoryCache这么个东西,用的时候发现在服务端有时会莫名其妙的丢失缓存并且丢失后就缓存不上了。本来网上关于使用MemoryCache的不多,一直也没有找到原因和解决办法,所以就自己仿着它写了一个简单的实现。
其中:
ChangeMoniter:是缓存对象的过期策略的检测器,包括文件改变监视器(FileChangeMoniter)和时间改变监视器(TimeChangeMoniter)
IMoniter:监视器接口,用来实现自定义扩展的监视器
IRemoveCache:定义了调用了MemoryCache回调函数删除缓存对象的接口。
MemoryCache:内存缓存类。
MemoryCacheEntry:缓存对象类。
MemoryCachePolicy:缓存过期策略类。
MemoryCacheManager:缓存管理器类。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using Cache.MemoryCache.Interface; namespace Cache.MemoryCache.Moniter { public class FileChangeMoniter:IMoniter { #region 变量 private FileSystemWatcher fileWatcher = null;//文件监视器对象 private string _filePath = string.Empty; private DateTime _activityTime;//对象的激活时间 private bool _isRemove = false;//该缓存对象是否移除 #endregion #region 属性 /// <summary> /// 文件路径 /// </summary> public string FilePath { get { return _filePath; } } public DateTime ActivityTime { get { return _activityTime; } } #endregion #region 构造函数 public FileChangeMoniter(string filePath) { this._filePath = filePath; SetFileWatcher(); } #endregion #region 文件监视器 /// <summary> /// 设置文件监视器 /// </summary> private void SetFileWatcher() { fileWatcher = new FileSystemWatcher(); fileWatcher.Path = this.FilePath.Substring(0, this.FilePath.LastIndexOf(@"\")); fileWatcher.Filter = this.FilePath.Substring(this.FilePath.LastIndexOf(@"\") + 1, this.FilePath.Length - 1 - this.FilePath.LastIndexOf(@"\")); fileWatcher.NotifyFilter = NotifyFilters.LastWrite; fileWatcher.EnableRaisingEvents = true; fileWatcher.Changed += fileWatcher_Changed; } /// <summary> /// 文件修改事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void fileWatcher_Changed(object sender, FileSystemEventArgs e) { _isRemove = true; } #endregion #region IMoniter接口方法 // 判断对象是否过期 public bool IsExpire() { return this._isRemove; } // 刷新对象激活时间 public void RefreshActivityTime(DateTime time) { this._activityTime = time; } #endregion
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Cache.MemoryCache.Interface; namespace Cache.MemoryCache.Moniter { public class TimeChangeMonitor:IMoniter { #region 变量 private DateTime _createTime;//创建时间 private DateTime _activityTime;//激活时间 private DateTime _disposeTime;//消除时间 private TimeSpan _spanTime;//相对时间 private TimeType _timeType; private bool _isRemove = false; #endregion #region 属性 public DateTime CreateTime { get { return _createTime; } } public DateTime ActivityTime { get { return _activityTime; } } public DateTime DisposeTime { get { return _disposeTime; } } public TimeSpan SpanTime { get { return _spanTime; } } public TimeType TimeType { get { return _timeType; } } #endregion #region 构造函数 public TimeChangeMonitor(DateTime disposeTime) { this._createTime = DateTime.Now; this._activityTime = this._createTime; this._disposeTime = disposeTime; this._timeType = TimeType.Absolute_Time; } public TimeChangeMonitor(TimeSpan spanTime) { this._createTime = DateTime.Now; this._activityTime = this._createTime; this._spanTime = spanTime; this._timeType = TimeType.Relative_Time; } #endregion /// <summary>比较绝对时间的过期策略</summary> /// <returns>过期:true,不过期:false</returns> private bool SetAbsoluteTime() { DateTime nowTime = DateTime.Now; if (nowTime.CompareTo(DisposeTime) < 0) { return false; } else { return true; } } /// <summary>比较相对时间的过期策略</summary> /// <returns>过期:true,不过期:false</returns> private bool SetRelativeTime() { DateTime endTime = this._activityTime + this._spanTime; DateTime nowTime = DateTime.Now; if (nowTime.CompareTo(endTime) < 0) { return false; } else { return true; } } #region IMoniter接口方法 // 判断对象是否过期 public bool IsExpire() { switch (_timeType) { case TimeType.Absolute_Time://绝对时间 _isRemove = SetAbsoluteTime(); break; case TimeType.Relative_Time://相对时间 _isRemove = SetRelativeTime(); break; } return _isRemove; } //刷新对象的激活时间 public void RefreshActivityTime(DateTime time) { this._activityTime = time; } #endregion
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Cache.MemoryCache.Interface { /// <summary> /// Moniter的回调方法接口 /// </summary> public interface IMoniter { /// <summary> /// 当前对象是否过期 /// </summary> /// <returns></returns> bool IsExpire(); /// <summary> /// 刷新激活时间 /// </summary> void RefreshActivityTime(DateTime time); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Cache.MemoryCache.Interface { /// <summary> /// 定义了调用了MemoryCache回调函数删除缓存对象的接口 /// </summary> internal interface IRemoveCache { /// <summary> /// 判断缓存对象是否过期并移除 /// </summary> /// <returns></returns> void CheckExpireAndRemove(); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Cache.MemoryCache.Interface; using Cache.MemoryCache.Moniter; namespace Cache.MemoryCache { public class MemoryCache { #region 属性 private string _name = string.Empty; private static readonly object lockobj = new object(); public string Name { get { return _name; } } private Dictionary<string, MemoryCacheEntry> _cache; #endregion #region 构造函数 private MemoryCache(string cacheName) { this._name = cacheName; this._cache = new Dictionary<string, MemoryCacheEntry>(); MemoryCacheManager.GetManager().Add(this); } #endregion #region 默认的MemoryCache private static MemoryCache _defaultMemoryCache; /// <summary>默认的MemoryCache</summary> public static MemoryCache DefaultCache { get { lock (lockobj)//多线程并发锁 { if (_defaultMemoryCache == null) { _defaultMemoryCache = new MemoryCache("Default"); } } return _defaultMemoryCache; } } #endregion #region 创建一个新的非默认的MemoryCache /// <summary> /// 该方法是获取一个新缓存对象 /// </summary> /// <param name="cacheName">MemoryCache名字</param> /// <returns></returns> public static MemoryCache GetMemoryCache(string cacheName) { if (MemoryCacheManager.GetManager().ContainCache(cacheName)) { return MemoryCacheManager.GetManager().Get(cacheName); } else { return new MemoryCache(cacheName); } } #endregion #region 缓存对象操作方法 /// <summary>将对象放入缓存</summary> /// <param name="key">缓存对象的key</param> /// <param name="value">需要缓存的对象</param> /// <param name="policy">缓存的处理策略</param> public void SetCache(string key, object value, MemoryCachePolicy policy) { lock (lockobj) { MemoryCacheEntry cacheEntry = new MemoryCacheEntry(this, key, value, policy); this._cache.Add(key, cacheEntry); //刷新激活时间 cacheEntry.RefreshActivityTime(); } } /// <summary>获取缓存对象</summary> /// <typeparam name="T">缓存对象类型</typeparam> /// <param name="key">缓存对象的key</param> /// <returns></returns> public T GetCache<T>(string key) { //判断缓存是否过期 CheckExpireAndRemove(key); if (_cache.ContainsKey(key)) { MemoryCacheEntry cacheEntry = this._cache[key]; //刷新激活时间 cacheEntry.RefreshActivityTime(); return (T)cacheEntry.Value; } else { throw new Exception(string.Format("不存在key为{0}的缓存对象", key)); } } /// <summary>从MemoryCache中移除缓存对象</summary> /// <param name="key">缓存对象的key</param> public void RemoveCache(string key) { if (_cache.ContainsKey(key)) { _cache.Remove(key); } } /// <summary>从MemoryCache中移除缓存对象(供MemoryCacheEntry的回调)</summary> /// <param name="cacheName"></param> /// <param name="key"></param> internal void RemoveCache(string cacheName, string key) { MemoryCacheManager.GetManager().Get(cacheName).RemoveCache(key); } public bool ContainCache(string key) { //判断缓存是否过期 CheckExpireAndRemove(key); return _cache.ContainsKey(key); } /// <summary> /// 判断缓存对象是否过期并移除 /// </summary> /// <returns></returns> private void CheckExpireAndRemove(string key) { if (_cache.ContainsKey(key)) { //MemoryCacheEntry cacheEntry = this._cache[key]; IRemoveCache cacheEntry = this._cache[key]; cacheEntry.CheckExpireAndRemove(); } } #endregion } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Cache.MemoryCache.Interface; using Cache.MemoryCache.Moniter; namespace Cache.MemoryCache { internal class MemoryCacheEntry:IRemoveCache { #region 变量 private MemoryCache _memoryCache; #endregion #region 属性 public MemoryCachePolicy CachePolicy { set; get; } public object Value { set; get; } public string Key { set; get; } #endregion #region 构造函数 public MemoryCacheEntry(MemoryCache memoryCache, string key, object value, MemoryCachePolicy policy) { this._memoryCache = memoryCache; this.Key = key; this.Value = value; this.CachePolicy = policy; } #endregion /// <summary> 刷新对象激活时间 </summary> public void RefreshActivityTime() { switch (CachePolicy.PolicyType) { case PolicyType.FileChange: CachePolicy.FileChangeMoniter.RefreshActivityTime(DateTime.Now); break; case PolicyType.TimeChange: CachePolicy.TimeChangeMoniter.RefreshActivityTime(DateTime.Now); break; case PolicyType.Custom: CachePolicy.CustomChangeMoniters.RefreshActivityTime(DateTime.Now); break; } } /// <summary>删除缓存对象</summary> /// <param name="cacheName"></param> /// <param name="key"></param> private void RemoveCache(string cacheName, string key) { this._memoryCache.RemoveCache(cacheName, key); } #region IRemoveCache接口方法 public void CheckExpireAndRemove() { bool isRemove = false; if (CachePolicy != null) { switch (CachePolicy.PolicyType) { case PolicyType.FileChange: isRemove = CachePolicy.FileChangeMoniter.IsExpire(); break; case PolicyType.TimeChange: isRemove = CachePolicy.TimeChangeMoniter.IsExpire(); break; case PolicyType.Custom: isRemove = CachePolicy.FileChangeMoniter.IsExpire(); break; } } if (isRemove) { //回调删除缓存对象 RemoveCache(this._memoryCache.Name, Key); } } #endregion } }
using System; using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Cache.MemoryCache.Interface; using Cache.MemoryCache.Moniter; namespace Cache.MemoryCache { public class MemoryCachePolicy { #region 变量 private PolicyType _policyType; #endregion #region 属性 /// <summary> /// Policy类型 /// </summary> public PolicyType PolicyType { get { return _policyType; } } /// <summary> /// 文件改变Moniter /// </summary> public FileChangeMoniter FileChangeMoniter { set; get; } /// <summary> /// 时间改变Moniter /// </summary> public TimeChangeMonitor TimeChangeMoniter { set; get; } /// <summary> /// 用来自定义扩展的Moniter /// </summary> public IMoniter CustomChangeMoniters { set; get; } #endregion #region 构造函数 public MemoryCachePolicy(PolicyType type) { this._policyType = type; } #endregion } public enum PolicyType { FileChange = 0, TimeChange = 1, Custom = 2 } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Cache.MemoryCache.Interface; using Cache.MemoryCache.Moniter; namespace Cache.MemoryCache { /// <summary> /// MemoryCache的管理工具类 /// 该类是单例类 /// </summary> internal class MemoryCacheManager { private static MemoryCacheManager _memoryCacheManager; private Dictionary<string, MemoryCache> _cacheManager = new Dictionary<string, MemoryCache>(); private static readonly object lockobj = new object(); private MemoryCacheManager() { } public static MemoryCacheManager GetManager() { lock (lockobj)//控制多线程的并发问题 { if (_memoryCacheManager == null) { _memoryCacheManager = new MemoryCacheManager(); } } return _memoryCacheManager; } /// <summary>将缓存对象存入缓存管理器</summary> /// <param name="memoryCache">MemoryCache对象</param> public void Add(MemoryCache memoryCache) { lock (lockobj) { if (_cacheManager.ContainsKey(memoryCache.Name)) { _cacheManager.Remove(memoryCache.Name); } _cacheManager.Add(memoryCache.Name, memoryCache); } } /// <summary>获取memoryCacheName对应的MemoryCache对象</summary> /// <param name="memoryCacheName">MemoryCache名称</param> /// <returns></returns> public MemoryCache Get(string memoryCacheName) { if (_cacheManager.ContainsKey(memoryCacheName)) { return _cacheManager[memoryCacheName]; } else { throw new Exception("MemoryCache缓存对象找不到!"); //return default(MemoryCache); } } /// <summary>判断当前的MemoryCache是否存在</summary> /// <param name="memoryCacheName"></param> /// <returns></returns> public bool ContainCache(string memoryCacheName) { if (_cacheManager.ContainsKey(memoryCacheName)) { return true; } else { return false; } } /// <summary>MemoryCacheManager索引器</summary> /// <param name="memoryCacheName">MemoryCache名称</param> /// <returns></returns> public MemoryCache this[string memoryCacheName] { get { if (_cacheManager.ContainsKey(memoryCacheName)) { return _cacheManager[memoryCacheName]; } else { throw new Exception("MemoryCache缓存对象找不到!"); //return default(MemoryCache); } } } } }
MemoryCache cache = MemoryCache.DefaultCache;//获取缓存 if (cache.ContainCache(CACHE_NAME) == false)//判断当前key的缓存对象是否存在 { //这里处理自己的逻辑 MemoryCachePolicy policy = new MemoryCachePolicy(PolicyType.TimeChange);//设置缓存策略 TimeChangeMonitor moniter = new TimeChangeMonitor(TimeSpan.FromSeconds(600));//设置相对时间的时间监视器 //TimeChangeMonitor moniter = new TimeChangeMonitor(DateTime.Now.AddSeconds(600));//设置绝对时间的时间监视器 policy.TimeChangeMoniter = moniter; //存入缓存 cache.SetCache(CACHE_NAME, dsCheck, policy); } else { //从缓存获取数据 dsCheck = cache.GetCache<DataSet>(CACHE_NAME);; }