简介

缓存是做什么的?

简单的可以认为是一个键值对的数据存于内存中,高速读取。作用为了减少和数据库的交互

Abp中缓存的使用

public class InvoiceAppService : ApplicationService
{
// 缓存管理器
private readonly ICacheManager _cacheManager;
// 仓储
private readonly IRepository<Invoice> _rep; public TestAppService(ICacheManager cacheMgr, IRepository<Invoice> rep)
{
_cacheManager;= cacheMgr;
_rep = rep;
} public void ChanelInvoice()
{
// 获取缓存
var cache = _cacheManager.GetCache("cache1");
// 转换强类型缓存
var typedCache = cache.AsTyped<int, string>();
// 获取缓存的值,存在则直接从缓存中取,不存在则按照你给定的方式取出值,然后添加进缓存中
// 这里是利用仓储从数据库中取出
var cacheValue = typedCache.Get(10, id => _rep.Get(id).Name);
}
}

Abp中的缓存可以看作一个大衣柜,里面有许多方格, 我们第一步 _cacheManager.GetCache得到的就是一个方格,里面有许多的value,value就是我们缓存的值.

在说的详细点,缓存分类里有user user里面有user1,user2... ,分类里还有invoice, invoice里面有invoice1,invoice2

我们都是从这个“分类里”取得具体的“缓存项”

ICacheManager

Abp框架使用的时候,取缓存,都是通过从ioc容器取出ICacheManager

public interface ICacheManager : IDisposable
{
// 获取所有缓存
IReadOnlyList<ICache> GetAllCaches();
// 根据名称取出缓存
[NotNull] ICache GetCache([NotNull] string name);
}

ICacheManager的默认实现是:CacheManagerBase(抽象类)实现了ISingletonDependency.在框架启动时会以单利的形式注册到ioc容器中.

public abstract class CacheManagerBase : ICacheManager, ISingletonDependency
{
// ioc管理器
protected readonly IIocManager IocManager;
// 缓存配置器
protected readonly ICachingConfiguration Configuration;
// 存放缓存的字典
protected readonly ConcurrentDictionary<string, ICache> Caches; // Constructor.
protected CacheManagerBase(IIocManager iocManager, ICachingConfiguration configuration)
{
IocManager = iocManager;
Configuration = configuration;
Caches = new ConcurrentDictionary<string, ICache>();
}
// 获取所有缓存
public IReadOnlyList<ICache> GetAllCaches()
{
return Caches.Values.ToImmutableList();// 转换成不可变集合
}
// 根据名称获取缓存 ICache
public virtual ICache GetCache(string name)
{ // 空值检测
Check.NotNull(name, nameof(name));
// 如果已经存在,则直接取出.
// 不存在则创建一个.
return Caches.GetOrAdd(name, (cacheName) =>
{ // 具体创建缓存的方法。该方法由具体的实现类,实现.
var cache = CreateCacheImplementation(cacheName);
// 获取缓存配置项 (c => c.CacheName == null 这是所有缓存的设置,后面会有说到)
var configurators = Configuration.Configurators.Where(c => c.CacheName == null || c.CacheName == cacheName);
// 为缓存设置 配置项中的配置(时间等..)
foreach (var configurator in configurators)
{
configurator.InitAction?.Invoke(cache);
} return cache;
});
}
// 释放
public virtual void Dispose()
{
DisposeCaches();
Caches.Clear();
}
// 调用ioc管理器依次释放
protected virtual void DisposeCaches()
{
foreach (var cache in Caches)
{
IocManager.Release(cache.Value);
}
}
// 实际创建缓存的方法.由子类实现.(可能是redis,或者memcache等)
protected abstract ICache CreateCacheImplementation(string name);
}

AbpMemoryCacheManager

AbpMemoryCacheManager是内存缓存管理器,是CacheManagerBase的其中一种实现

public class AbpMemoryCacheManager : CacheManagerBase
{ // 日志
public ILogger Logger { get; set; }
// ctor
public AbpMemoryCacheManager(IIocManager iocManager, ICachingConfiguration configuration)
: base(iocManager, configuration)
{
Logger = NullLogger.Instance;
}
// 重写CacheManagerBase的CreateCacheImplementation方法,创建AbpMemoryCache
protected override ICache CreateCacheImplementation(string name)
{
return new AbpMemoryCache(name)
{
Logger = Logger
};
}
// 释放
protected override void DisposeCaches()
{
foreach (var cache in Caches.Values)
{
cache.Dispose();
}
}
}

下面看看AbpMemoryCache是什么.

public class AbpMemoryCache : CacheBase
{
private MemoryCache _memoryCache;
// ctor
public AbpMemoryCache(string name)
: base(name)
{
_memoryCache = new MemoryCache(new OptionsWrapper<MemoryCacheOptions>(new MemoryCacheOptions()));
}
// 根据key获取值
public override object GetOrDefault(string key)
{
return _memoryCache.Get(key);
}
// 设置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);
}
}
// 根据key移除
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();
}
}

就是对memoryCache做了一层封装.

AbpRedisCacheManager

public class AbpRedisCacheManager : CacheManagerBase
{
public AbpRedisCacheManager(IIocManager iocManager, ICachingConfiguration configuration)
: base(iocManager, configuration)
{ // 瞬时注册AbpRedisCache
IocManager.RegisterIfNot<AbpRedisCache>(DependencyLifeStyle.Transient);
}
// 实现基类的CreateCacheImplementation方法 创建缓存
protected override ICache CreateCacheImplementation(string name)
{ // 从ioc容器中获取,这里需要name作为参数(如果你对ioc容器创建对象这个过程了解的话,就知道我说的是什么)
return IocManager.Resolve<AbpRedisCache>(new { name });
}
}

这个就是redis的实现,主要还是AbpRedisCache,这个和AbpMemoryCache一样,都是做了一层封装,其内部就是对redis的使用的封装啦

ICache

AbpRedisCache和AbpMemoryCache都是根据ICache实现的。

public interface ICache : IDisposable
{
// 缓存名字(唯一的)
string Name { get; }
// 滑动过期时间,默认 1h 可以通过configuration设置
TimeSpan DefaultSlidingExpireTime { get; set; }
// 绝对过期时间 默认是null.
TimeSpan? DefaultAbsoluteExpireTime { get; set; }
// 获取缓存数据,不存在则执行 Func 委托
object Get(string key, Func<string, object> factory);
// 上面方法做了批量处理
object[] Get(string[] keys, Func<string, object> factory);
// 异步获取
Task<object> GetAsync(string key, Func<string, Task<object>> factory);
// 同上
Task<object[]> GetAsync(string[] keys, Func<string, Task<object>> factory); // 获取缓存数据,没有的话为null
object GetOrDefault(string key);
// 批量
object[] GetOrDefault(string[] keys);
// 异步处理
Task<object> GetOrDefaultAsync(string key);
Task<object[]> GetOrDefaultAsync(string[] keys);
// 设置缓存
void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
void Set(KeyValuePair<string, object>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
// 异步处理
Task SetAsync(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
Task SetAsync(KeyValuePair<string, object>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
// 根据key移除缓存
void Remove(string key);
void Remove(string[] keys);
Task RemoveAsync(string key);
Task RemoveAsync(string[] keys);
// 清除该缓存下的所有数据
void Clear();
Task ClearAsync();
}

强类型缓存

CacheExtensions是ICache的扩展.

public static class CacheExtensions
{
// 其他代码 // 转换强类型缓存
public static ITypedCache<TKey, TValue> AsTyped<TKey, TValue>(this ICache cache)
{
return new TypedCacheWrapper<TKey, TValue>(cache);
} // 其他代码
}

通过ICache转换成强类型缓存,那么我们的缓存的值 也是强类型的了,不需要在手动强转了

可以看到上述代码中new了TypedCacheWrapper

public class TypedCacheWrapper<TKey, TValue> : ITypedCache<TKey, TValue>
{
// 具体调用AsTyped这个静态方法的Icache对象
public ICache InternalCache { get; private set; }
public TypedCacheWrapper(ICache internalCache)
{
InternalCache = internalCache;
}
// 缓存名字
public string Name
{
get { return InternalCache.Name; }
}
// 滑动过期时间
public TimeSpan DefaultSlidingExpireTime
{
get { return InternalCache.DefaultSlidingExpireTime; }
set { InternalCache.DefaultSlidingExpireTime = value; }
}
// 绝对过期时间
public TimeSpan? DefaultAbsoluteExpireTime
{
get { return InternalCache.DefaultAbsoluteExpireTime; }
set { InternalCache.DefaultAbsoluteExpireTime = value; }
}
// 释放
public void Dispose()
{
InternalCache.Dispose();
}
// 清空
public void Clear()
{
InternalCache.Clear();
} public Task ClearAsync()
{
return InternalCache.ClearAsync();
}
// 取 删 。。。。 其实调用的还是ICache的扩展方法
// return (TValue)cache.Get(key.ToString(), (k) => (object)factory(key));
// 最后还是做了强转
public TValue Get(TKey key, Func<TKey, TValue> factory)
{
return InternalCache.Get(key, factory);
} public TValue[] Get(TKey[] keys, Func<TKey, TValue> factory)
{
return InternalCache.Get(keys, factory);
} public Task<TValue> GetAsync(TKey key, Func<TKey, Task<TValue>> factory)
{
return InternalCache.GetAsync(key, factory);
} public Task<TValue[]> GetAsync(TKey[] keys, Func<TKey, Task<TValue>> factory)
{
return InternalCache.GetAsync(keys, factory);
} public TValue GetOrDefault(TKey key)
{
return InternalCache.GetOrDefault<TKey, TValue>(key);
} public TValue[] GetOrDefault(TKey[] keys)
{
return InternalCache.GetOrDefault<TKey, TValue>(keys);
} public Task<TValue> GetOrDefaultAsync(TKey key)
{
return InternalCache.GetOrDefaultAsync<TKey, TValue>(key);
} public Task<TValue[]> GetOrDefaultAsync(TKey[] keys)
{
return InternalCache.GetOrDefaultAsync<TKey, TValue>(keys);
} public void Set(TKey key, TValue value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
{
InternalCache.Set(key.ToString(), value, slidingExpireTime, absoluteExpireTime);
} public void Set(KeyValuePair<TKey, TValue>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
{
var stringPairs = pairs.Select(p => new KeyValuePair<string, object>(p.Key.ToString(), p.Value));
InternalCache.Set(stringPairs.ToArray(), slidingExpireTime, absoluteExpireTime);
} public Task SetAsync(TKey key, TValue value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
{
return InternalCache.SetAsync(key.ToString(), value, slidingExpireTime, absoluteExpireTime);
} public Task SetAsync(KeyValuePair<TKey, TValue>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
{
var stringPairs = pairs.Select(p => new KeyValuePair<string, object>(p.Key.ToString(), p.Value));
return InternalCache.SetAsync(stringPairs.ToArray(), slidingExpireTime, absoluteExpireTime);
} public void Remove(TKey key)
{
InternalCache.Remove(key.ToString());
} public void Remove(TKey[] keys)
{
InternalCache.Remove(keys.Select(key => key.ToString()).ToArray());
} public Task RemoveAsync(TKey key)
{
return InternalCache.RemoveAsync(key.ToString());
} public Task RemoveAsync(TKey[] keys)
{
return InternalCache.RemoveAsync(keys.Select(key => key.ToString()).ToArray());
}
}

ICachingConfiguration

缓存的一些设置。如过期时间等,则是通过ICachingConfiguration进行设置的。而ICachingConfiguration,则是在AbpBootstrap的初始化方法中进行注入的

public virtual void Initialize()
{
IocManager.IocContainer.Install(new AbpCoreInstaller());
}
internal class AbpCoreInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
// 其他配置组建(略)..
Component.For<ICachingConfiguration, CachingConfiguration>().ImplementedBy<CachingConfiguration>().LifestyleSingleton()
);
}
}

最后会变为IAbpStartupConfiguration的一个属性(Caching),有因为AbpModule中有IAbpStartupConfiguration这个属性,所以我们可以在自己的模块的预初始化方法中对缓存进行一系列的设置

public override void PreInitialize()
{
Configuration.Caching.ConfigureAll(z=>z.DefaultSlidingExpireTime = TimeSpan.FromHours(1));
}

在来看看CachingConfiguration

internal class CachingConfiguration : ICachingConfiguration
{
public IAbpStartupConfiguration AbpConfiguration { get; private set; }
// 缓存配置器集合
private readonly List<ICacheConfigurator> _configurators;
public IReadOnlyList<ICacheConfigurator> Configurators
{
get { return _configurators.ToImmutableList(); }
}
// ctor
public CachingConfiguration(IAbpStartupConfiguration abpConfiguration)
{
AbpConfiguration = abpConfiguration;
_configurators = new List<ICacheConfigurator>();
}
// 为所有缓存设置 一些配置.
public void ConfigureAll(Action<ICache> initAction)
{
_configurators.Add(new CacheConfigurator(initAction));
}
// 为指定名称的缓存 设置一些配置。
public void Configure(string cacheName, Action<ICache> initAction)
{
_configurators.Add(new CacheConfigurator(cacheName, initAction));
}
}
internal class CacheConfigurator : ICacheConfigurator
{
// 缓存名字
public string CacheName { get; private set; }
// 执行的配置操作
public Action<ICache> InitAction { get; private set; } public CacheConfigurator(Action<ICache> initAction)
{
InitAction = initAction;
}
public CacheConfigurator(string cacheName, Action<ICache> initAction)
{
CacheName = cacheName;
InitAction = initAction;
}
}

在IcacheManager的默认实现CacheManagerBase中,创建缓存后会获取CacheConfigurator并执行InitAction.Invoke方法对缓存进行设置,而InitAction则是我们在模块的预初始化方法中定义的.

根据ConfigureAll和Configure方法可以看出,你在初始化的时候,ConfigureAll是会初始化一个cacheName=null的 CacheConfigurator

而Configure则是一个指定名称的CacheConfigurator

这也是为什么,CacheManagerBase中获取所有缓存配置,是这样过滤的,

获取所有缓存都要的配置 以及 指定缓存 自己的配置

var configurators = Configuration.Configurators.Where(c => c.CacheName == null || c.CacheName == cacheName);

可以借鉴的地方

在缓存这一块,ABP用了两个设计模式:

模板方法模式:父类实现主要算法,定义调用顺序和过程,子类实现具体算法,CacheManagerBase,AbpMemoryCacheManager,AbpRedisCacheManager

桥接模式:ICacheManager,ICache 独立变化Manager和Cache,使Manager和Cache可以独自扩展

最新文章

  1. js拖拽效果实现
  2. asp.net执行SqlServer存储过程!(详解!)
  3. Win10 UWP 开发系列:使用多语言工具包让应用支持多语言
  4. STM32F之IAR6.5 J-Link程序下载错误
  5. poj2774 后缀数组2个字符串的最长公共子串
  6. OLAP的一些知识——接下去的项目需要的背景
  7. C++学习笔记(十):类
  8. LINQ Enumerable 续 II
  9. python3.4+pyspider爬58同城(二)
  10. 严重:IOException while loading persisted sessions:java.io.EOFException.
  11. nginx虚拟域名的配置以及测试验证
  12. 后端分布式系列:分布式存储-HDFS 异常处理与恢复
  13. 使用可变对象作为python函数默认参数引发的问题
  14. 【webpack学习笔记】a03-管理输出
  15. C语言结构体变量私有化
  16. com.android.jack.CommandLine: Internal compiler error
  17. 获取Tomcat更详细的日志
  18. iOS程序main函数之前发生了什么
  19. Java 使用Log4J进行日志操作
  20. commit和rollback

热门文章

  1. 内网批量测试登录机器工具,并且dir 目标机器c盘
  2. Qt qobject_cast用法 向下转型
  3. HDU3047 Zjnu Stadium
  4. 03_01_基本操作_增(insert)
  5. review40
  6. WPF各种控件详解——(WPF从我炫系列)
  7. 5.2 Selenium2环境搭建
  8. 解决:return _compile(pattern, flags).search(string) TypeError: expected string or buffer
  9. android问题 This version of android studio is incompatible with the gradle version used.
  10. excel中日期设置星期