一、简介
CacheManager是一款开源组件,地址是https://github.com/MichaCo/CacheManager;
里面不但有详细的简介,还有很多demo,demo的地址是https://cachemanager.michaco.net/documentation。
好像没有中文网页,大家将就着看吧!这里就不再赘述了。
二、封装
1)引用
通过Nuget引用三个组件:CacheManager.Core、CacheManager.SystemRuntimeCaching、CacheManager.StackExchange.Redis
CacheManager.Core是核心类,一定要引用.。
CacheManager.SystemRuntimeCaching是.net自带缓存的实现,使用高速缓存;
CacheManager.StackExchange.Redis是redis缓存的实现,适用于分布式缓存。
当然,并不是说我们引用了就必须使用,在实际项目中可能没有用到Redis,那么我们配置中不使用即可。
2)操作
把缓存操作封装成一个静态类:CacheUtils。
由于CacheManager并没有提供关于所有Key的读取方法或者属性,我们就定义了一个属性CacheKeys,在事件中维护这些缓存键。
缓存操作提供了增加/移除方法,如果缓存键已存在,增加将覆盖原数据。
using System;
using System.Collections.Generic;
using System.Linq;
using CacheManager.Core;
namespace CacheManagerDemo
{
/// <summary>
/// 缓存工具类,整合了cachemanager <br/>
/// 开源地址:https://github.com/MichaCo/CacheManager"
/// </summary>
public static class CacheUtils
{
private static readonly ICacheManager<object> cache;
/// <summary>
/// 缓存键集合,region "_" key,如果没有指定region,那么就用global
/// </summary>
public static List<string> CacheKeys { get; set; }
/// <summary>
/// 初始化
/// </summary>
static CacheUtils()
{
if (CacheKeys == null) CacheKeys = new List<string>(); //初始化
cache = CacheFactory.Build("ctt_web_caches", settings =>
{
if (CacheConfig.CacheType == CacheType.RedisCache.ToString())
{
settings
.WithSystemRuntimeCacheHandle("frontCache") //前端使用服务器缓存
.And
.WithRedisConfiguration("redisBackCache", config => //Redis缓存配置
{
config.WithAllowAdmin()
.WithDatabase(0)
.WithEndpoint(CacheConfig.RedisServer, CacheConfig.RedisPort) //redis服务
.WithPassword(CacheConfig.RedisPwd) //密码
.EnableKeyspaceEvents();
})
.WithMaxRetries(1000)//尝试次数
.WithRetryTimeout(100)//尝试超时时间
.WithRedisBackplane("redisBackCache") //Redis做为后台缓存,内存缓存做为前台缓存,Redis缓存会和内存缓存同步
.WithRedisCacheHandle("redisBackCache", true);//redis缓存handle
}
else
{
settings.WithSystemRuntimeCacheHandle("frontCache");
}
});
#region 缓存事件
/*以下操作会影响到key集合*/
cache.OnAdd = (s, arg) =>
{
string key = string.IsNullOrEmpty(arg.Region) ? "global_" arg.Key : arg.Region "_" arg.Key;
if (!CacheKeys.Contains(key))
CacheKeys.Add(key);
};
cache.OnPut = (s, arg) =>
{
string key = string.IsNullOrEmpty(arg.Region) ? "global_" arg.Key : arg.Region "_" arg.Key;
if (!CacheKeys.Contains(key))
CacheKeys.Add(key);
};
cache.OnRemove = (s, arg) => { CacheKeys.Remove((string.IsNullOrEmpty(arg.Region) ? "global" : arg.Region) "_" arg.Key); };
cache.OnClearRegion = (s, arg) => { CacheKeys.RemoveAll(x => x.StartsWith(arg.Region "_")); };
cache.OnClear = (s, arg) => { CacheKeys.RemoveAll(x => true); };
cache.OnRemoveByHandle = (s, arg) => { CacheKeys.Remove((string.IsNullOrEmpty(arg.Region) ? "global" : arg.Region) "_" arg.Key); };
#endregion
}
#region 缓存操作
/// <summary>
/// 是否存在缓存
/// </summary>
/// <param name="key"></param>
/// <param name="region"></param>
/// <returns></returns>
public static bool Exists(string key, string region = null)
{
return !string.IsNullOrEmpty(region)
? cache.Exists(key, region)
: cache.Exists(key);
}
/// <summary>
/// 添加缓存
/// </summary>
/// <param name="key">键</param>
/// <param name="obj">值对象</param>
/// <param name="expires">超地时间(秒),默认24小时</param>
/// <param name="region">域</param>
public static void Insert(string key, object obj, int expires = 3600 * 24, string region = null)
{
var item = !string.IsNullOrEmpty(region)
? new CacheItem<object>(key, region, obj, ExpirationMode.Sliding, TimeSpan.FromSeconds(expires))
: new CacheItem<object>(key, obj, ExpirationMode.Sliding, TimeSpan.FromSeconds(expires));
cache.Put(item);
}
/// <summary>
/// 读缓存
/// </summary>
/// <param name="key"></param>
/// <param name="region"></param>
/// <returns></returns>
public static object Get(string key, string region = null)
{
return !string.IsNullOrEmpty(region)
? cache.Get(key, region)
: cache.Get(key);
}
/// <summary>
/// 读缓存
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key"></param>
/// <param name="region"></param>
/// <returns></returns>
public static T Get<T>(string key, string region = null)
{
var obj = Get(key, region);
return obj != null
? (T)obj
: default(T);
}
/// <summary>
/// 查找域的所有键
/// </summary>
/// <param name="region"></param>
/// <returns></returns>
public static IEnumerable<string> GetKeys(string region)
{
if (CacheKeys == null) return null;
return CacheKeys.Where(p => p.StartsWith(region "_")).ToList();
}
/// <summary>
/// 删除缓存
/// </summary>
/// <param name="key"></param>
/// <param name="region"></param>
public static void Remove(string key, string region = null)
{
if (!string.IsNullOrEmpty(region))
cache.Remove(key, region);
else
cache.Remove(key); //即使没有这个key也不会报错
}
/// <summary>
/// 清除缓存
/// </summary>
/// <param name="region"></param>
public static void Clear(string region = null)
{
if (!string.IsNullOrEmpty(region))
cache.ClearRegion(region);
else
cache.Clear();
}
#endregion
}
}
三、测试
1)redis配置
如果还没有安装Redis服务,可以在https://github.com/tporadowski/redis/releases下载并安装成服务。
然后在App.config或者Web.config的AppSetting中进行配置
<appSettings>
<!--缓存类型:LocalCache / RedisCache,如果配置成RedisCache,需要安装Redis服务-->
<add key="CacheType" value="LocalCache"/>
<!--Redis服务址址-->
<add key="RedisServer" value="localhost"/>
<!--Redis服务端口-->
<add key="RedisPort" value="6379"/>
<!--Redis服务密码-->
<add key="RedisPwd" value="jasonlee"/>
<!--Redis服务使用的数据库序号-->
<add key="DBNum" value="0"/>
</appSettings>
这些配置在上面的工具类中使用,还需要一个读配置的类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CacheManagerDemo
{
public enum CacheType
{
LocalCache,
RedisCache
}
public static class CacheConfig
{
public static string CacheType { get; set; }
public static string RedisServer { get; set; }
public static int RedisPort { get; set; } = 6379;
public static string RedisPwd { get; set; }
public static int DBNum { get; set; } = 0;
static CacheConfig()
{
ReadConfig(); //初始化
}
public static void ReadConfig()
{
CacheType = System.Configuration.ConfigurationManager.AppSettings["CacheType"];
RedisServer = System.Configuration.ConfigurationManager.AppSettings["RedisServer"];
var intRedisPort = 6379;
var strRedisPort = System.Configuration.ConfigurationManager.AppSettings["RedisPort"];
if (int.TryParse(strRedisPort, out intRedisPort))
RedisPort = intRedisPort;
RedisPwd = System.Configuration.ConfigurationManager.AppSettings["RedisPwd"];
var intDBNum = 0;
var strDBNum = System.Configuration.ConfigurationManager.AppSettings["DBNum"];
if (int.TryParse(strRedisPort, out intDBNum))
DBNum = intDBNum;
}
}
}
2)测试类
最后我们造一个测试数据,验证是否正确
using System;
namespace CacheManagerDemo
{
class Program
{
static void Main(string[] args)
{
//添加普通缓存
CacheUtils.Insert("key1", "123");
//添加对象缓存
CacheUtils.Insert("key2", new Student() { Name = "jasonlee", Age = 18 });
//添加到域
CacheUtils.Insert("key3", "456", 3600 * 24, "region1");
CacheUtils.Insert("key3.1", "789", 3600 * 24, "region1");
//添加很短时间的缓存
CacheUtils.Insert("key4", "shorttime", 1); //1秒过后就超时,系统会自动删除这个key
//读取缓存
Console.WriteLine("共有缓存键:{0}", CacheUtils.CacheKeys.Count);
Console.WriteLine("-----------------------");
foreach (var key in CacheUtils.CacheKeys)
{
Console.WriteLine("缓存键:{0}", key);
}
Console.WriteLine("-----------------------");
Console.WriteLine("key1:{0}", CacheUtils.Get("key1").ToString());
Console.WriteLine("key2:{0}", CacheUtils.Get<Student>("key2").Name);
Console.WriteLine("key3:{0}", CacheUtils.Get("key3", "region1").ToString());
//模拟延迟5秒
Console.WriteLine("key4:{0}", CacheUtils.Get("key4").ToString());
System.Threading.Thread.Sleep(5000);
Console.WriteLine("已经过去了5秒...");
Console.WriteLine("key4:{0}", CacheUtils.Get("key4") == null ? "不存在" : CacheUtils.Get("key4").ToString());
Console.WriteLine("共有缓存键:{0}", CacheUtils.CacheKeys.Count);
//清除缓存key1
CacheUtils.Remove("key1");
Console.WriteLine("是否存在key1:{0}", CacheUtils.Exists("key1") ? "存在" : "不存在");
//清除域的缓存
CacheUtils.Clear("region1");
Console.WriteLine("清除域region1后共有缓存键:{0}", CacheUtils.CacheKeys.Count);
Console.WriteLine("-----------------------");
foreach (var key in CacheUtils.CacheKeys)
{
Console.WriteLine("缓存键:{0}", key);
}
Console.WriteLine("-----------------------");
//清除所有缓存
CacheUtils.Clear();
Console.WriteLine("清空缓存后数量:{0}", CacheUtils.CacheKeys.Count);
Console.WriteLine("We are done...");
Console.ReadKey();
}
}
[Serializable]
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
}
最后,我们打开Redis客户端,查看是否写入了数据