这里先来看看他的实现:
public class AbpRedisCacheManager : CacheManagerBase { public AbpRedisCacheManager(IIocManager iocManager, ICachingConfiguration configuration) : base(iocManager, configuration) { // 注册 Redis 缓存 IocManager.RegisterIfNot<AbpRedisCache>(DependencyLifeStyle.Transient); } protected override ICache CreateCacheImplementation(string name) { // 解析已经注入的 Redis 缓存 // 这里可以看到解析的时候如何传入构造参数 return IocManager.Resolve<AbpRedisCache>(new { name }); } }一样的,非常简单,没什么可以说的。
2.2 缓存我们从缓存管理器当中拿到具体的缓存之后才能够进行真正的缓存操作,这里需要明确的一个概念是缓存是一个缓存项的集合,缓存项里面的值才是我们真正缓存的结果。
就如同一个用户表,他拥有多条用户数据,那么我们要针对这个用户表做缓存,就会创建一个缓存名称叫做 "用户表" 的缓存,在需要获得用户数据的时候,我们拿去数据就直接从这个 "用户表" 缓存当中取得具体的缓存项,也就是具体的用户数据。
其实每个缓存也是几个 键值对 ,键就是缓存的键,以上面的 "用户表缓存" 为例子,那么他缓存项的键就是 int 型的 Id ,他的值呢就是一个用户实体。
2.2.1 基本定义所有缓存的定义都在 ICache 当中,每个缓存都拥有增删查改这些基本操作,并且还拥有过期时间与名称等属性。
同样,缓存也有一个抽象基类的实现,名字叫做 CacheBase 。与缓存管理器的抽象基类一样,CacheBase 内部仅实现了 Get 方法的基本逻辑,其他的都是抽象方法,需要由具体的类型进行实现。
2.2.2 内存缓存的实现这里我们以 Abp 的默认 MemoryCache 实现为例子来看看里面是什么构造:
public class AbpMemoryCache : CacheBase { private MemoryCache _memoryCache; // 初始化 MemoryCahce public AbpMemoryCache(string name) : base(name) { _memoryCache = new MemoryCache(new OptionsWrapper<MemoryCacheOptions>(new MemoryCacheOptions())); } // 从 MemoryCahce 取得缓存 public override object GetOrDefault(string key) { return _memoryCache.Get(key); } // 设置缓存 public override void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null) { // 值为空的时候抛出异常 if (value == null) { throw new AbpException("Can not insert null values to the cache!"); } if (absoluteExpireTime != null) { _memoryCache.Set(key, value, DateTimeOffset.Now.Add(absoluteExpireTime.Value)); } else if (slidingExpireTime != null) { _memoryCache.Set(key, value, slidingExpireTime.Value); } else if (DefaultAbsoluteExpireTime != null) { _memoryCache.Set(key, value, DateTimeOffset.Now.Add(DefaultAbsoluteExpireTime.Value)); } else { _memoryCache.Set(key, value, DefaultSlidingExpireTime); } } // 删除缓存 public override void Remove(string key) { _memoryCache.Remove(key); } // 清空缓存 public override void Clear() { _memoryCache.Dispose(); _memoryCache = new MemoryCache(new OptionsWrapper<MemoryCacheOptions>(new MemoryCacheOptions())); } public override void Dispose() { _memoryCache.Dispose(); base.Dispose(); } }可以看到在 AbpMemoryCache 内部就是将 MemoryCahce 进行了一个二次包装而已。
其实可以看到这些缓存超期时间之类的参数 Abp 自己并没有用到,而是将其传递给具体的缓存实现来进行管理。
2.2.3 Redis 缓存的实现Abp.Redis 库使用的是 StackExchange.Redis 库来实现对 Redis 的通讯的,其实现为 AbpRedisCache ,里面也没什么好说的,如同内存缓存一样,实现那些抽象方法就可以了。
public class AbpRedisCache : CacheBase { private readonly IDatabase _database; private readonly IRedisCacheSerializer _serializer; public AbpRedisCache( string name, IAbpRedisCacheDatabaseProvider redisCacheDatabaseProvider, IRedisCacheSerializer redisCacheSerializer) : base(name) { _database = redisCacheDatabaseProvider.GetDatabase(); _serializer = redisCacheSerializer; } // 获取缓存 public override object GetOrDefault(string key) { var objbyte = _database.StringGet(GetLocalizedKey(key)); return objbyte.HasValue ? Deserialize(objbyte) : null; } public override void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null) { if (value == null) { throw new AbpException("Can not insert null values to the cache!"); } //TODO: 这里是一个解决实体序列化的方法. //TODO: 通常实体不应该存储在缓存当中,目前 Abp.Zero 包是这样来进行处理的,这个问题将会在未来被修正. var type = value.GetType(); if (EntityHelper.IsEntity(type) && type.GetAssembly().FullName.Contains("EntityFrameworkDynamicProxies")) { type = type.GetTypeInfo().BaseType; } _database.StringSet( GetLocalizedKey(key), Serialize(value, type), absoluteExpireTime ?? slidingExpireTime ?? DefaultAbsoluteExpireTime ?? DefaultSlidingExpireTime ); } // 移除缓存 public override void Remove(string key) { _database.KeyDelete(GetLocalizedKey(key)); } // 清空缓存 public override void Clear() { _database.KeyDeleteWithPrefix(GetLocalizedKey("*")); } // 序列化对象 protected virtual string Serialize(object value, Type type) { return _serializer.Serialize(value, type); } // 反序列化对象 protected virtual object Deserialize(RedisValue objbyte) { return _serializer.Deserialize(objbyte); } // 获得缓存的 Key protected virtual string GetLocalizedKey(string key) { return "n:" + Name + ",c:" + key; } } 2.3 缓存配置