简介
缓存是作什么的?
简单的能够认为是一个键值对的数据存于内存中,高速读取。做用为了减小和数据库的交互redis
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是什么.app
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实现的。ide
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的扩展.this
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能够独自扩展