简介

缓存是做什么的?

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

Abp中缓存的使用

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

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

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

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

ICacheManager

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

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

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

  1. public abstract class CacheManagerBase : ICacheManager, ISingletonDependency
  2. {
  3. // ioc管理器
  4. protected readonly IIocManager IocManager;
  5. // 缓存配置器
  6. protected readonly ICachingConfiguration Configuration;
  7. // 存放缓存的字典
  8. protected readonly ConcurrentDictionary<string, ICache> Caches;
  9. // Constructor.
  10. protected CacheManagerBase(IIocManager iocManager, ICachingConfiguration configuration)
  11. {
  12. IocManager = iocManager;
  13. Configuration = configuration;
  14. Caches = new ConcurrentDictionary<string, ICache>();
  15. }
  16. // 获取所有缓存
  17. public IReadOnlyList<ICache> GetAllCaches()
  18. {
  19. return Caches.Values.ToImmutableList();// 转换成不可变集合
  20. }
  21. // 根据名称获取缓存 ICache
  22. public virtual ICache GetCache(string name)
  23. { // 空值检测
  24. Check.NotNull(name, nameof(name));
  25. // 如果已经存在,则直接取出.
  26. // 不存在则创建一个.
  27. return Caches.GetOrAdd(name, (cacheName) =>
  28. { // 具体创建缓存的方法。该方法由具体的实现类,实现.
  29. var cache = CreateCacheImplementation(cacheName);
  30. // 获取缓存配置项 (c => c.CacheName == null 这是所有缓存的设置,后面会有说到)
  31. var configurators = Configuration.Configurators.Where(c => c.CacheName == null || c.CacheName == cacheName);
  32. // 为缓存设置 配置项中的配置(时间等..)
  33. foreach (var configurator in configurators)
  34. {
  35. configurator.InitAction?.Invoke(cache);
  36. }
  37. return cache;
  38. });
  39. }
  40. // 释放
  41. public virtual void Dispose()
  42. {
  43. DisposeCaches();
  44. Caches.Clear();
  45. }
  46. // 调用ioc管理器依次释放
  47. protected virtual void DisposeCaches()
  48. {
  49. foreach (var cache in Caches)
  50. {
  51. IocManager.Release(cache.Value);
  52. }
  53. }
  54. // 实际创建缓存的方法.由子类实现.(可能是redis,或者memcache等)
  55. protected abstract ICache CreateCacheImplementation(string name);
  56. }

AbpMemoryCacheManager

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

  1. public class AbpMemoryCacheManager : CacheManagerBase
  2. { // 日志
  3. public ILogger Logger { get; set; }
  4. // ctor
  5. public AbpMemoryCacheManager(IIocManager iocManager, ICachingConfiguration configuration)
  6. : base(iocManager, configuration)
  7. {
  8. Logger = NullLogger.Instance;
  9. }
  10. // 重写CacheManagerBase的CreateCacheImplementation方法,创建AbpMemoryCache
  11. protected override ICache CreateCacheImplementation(string name)
  12. {
  13. return new AbpMemoryCache(name)
  14. {
  15. Logger = Logger
  16. };
  17. }
  18. // 释放
  19. protected override void DisposeCaches()
  20. {
  21. foreach (var cache in Caches.Values)
  22. {
  23. cache.Dispose();
  24. }
  25. }
  26. }

下面看看AbpMemoryCache是什么.

  1. public class AbpMemoryCache : CacheBase
  2. {
  3. private MemoryCache _memoryCache;
  4. // ctor
  5. public AbpMemoryCache(string name)
  6. : base(name)
  7. {
  8. _memoryCache = new MemoryCache(new OptionsWrapper<MemoryCacheOptions>(new MemoryCacheOptions()));
  9. }
  10. // 根据key获取值
  11. public override object GetOrDefault(string key)
  12. {
  13. return _memoryCache.Get(key);
  14. }
  15. // 设置key和值
  16. public override void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
  17. {
  18. if (value == null)
  19. {
  20. throw new AbpException("Can not insert null values to the cache!");
  21. }
  22. if (absoluteExpireTime != null)
  23. {
  24. _memoryCache.Set(key, value, DateTimeOffset.Now.Add(absoluteExpireTime.Value));
  25. }
  26. else if (slidingExpireTime != null)
  27. {
  28. _memoryCache.Set(key, value, slidingExpireTime.Value);
  29. }
  30. else if (DefaultAbsoluteExpireTime != null)
  31. {
  32. _memoryCache.Set(key, value, DateTimeOffset.Now.Add(DefaultAbsoluteExpireTime.Value));
  33. }
  34. else
  35. {
  36. _memoryCache.Set(key, value, DefaultSlidingExpireTime);
  37. }
  38. }
  39. // 根据key移除
  40. public override void Remove(string key)
  41. {
  42. _memoryCache.Remove(key);
  43. }
  44. // 清空
  45. public override void Clear()
  46. {
  47. _memoryCache.Dispose();
  48. _memoryCache = new MemoryCache(new OptionsWrapper<MemoryCacheOptions>(new MemoryCacheOptions()));
  49. }
  50. // 释放
  51. public override void Dispose()
  52. {
  53. _memoryCache.Dispose();
  54. base.Dispose();
  55. }
  56. }

就是对memoryCache做了一层封装.

AbpRedisCacheManager

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

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

ICache

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

  1. public interface ICache : IDisposable
  2. {
  3. // 缓存名字(唯一的)
  4. string Name { get; }
  5. // 滑动过期时间,默认 1h 可以通过configuration设置
  6. TimeSpan DefaultSlidingExpireTime { get; set; }
  7. // 绝对过期时间 默认是null.
  8. TimeSpan? DefaultAbsoluteExpireTime { get; set; }
  9. // 获取缓存数据,不存在则执行 Func 委托
  10. object Get(string key, Func<string, object> factory);
  11. // 上面方法做了批量处理
  12. object[] Get(string[] keys, Func<string, object> factory);
  13. // 异步获取
  14. Task<object> GetAsync(string key, Func<string, Task<object>> factory);
  15. // 同上
  16. Task<object[]> GetAsync(string[] keys, Func<string, Task<object>> factory);
  17. // 获取缓存数据,没有的话为null
  18. object GetOrDefault(string key);
  19. // 批量
  20. object[] GetOrDefault(string[] keys);
  21. // 异步处理
  22. Task<object> GetOrDefaultAsync(string key);
  23. Task<object[]> GetOrDefaultAsync(string[] keys);
  24. // 设置缓存
  25. void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
  26. void Set(KeyValuePair<string, object>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
  27. // 异步处理
  28. Task SetAsync(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
  29. Task SetAsync(KeyValuePair<string, object>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
  30. // 根据key移除缓存
  31. void Remove(string key);
  32. void Remove(string[] keys);
  33. Task RemoveAsync(string key);
  34. Task RemoveAsync(string[] keys);
  35. // 清除该缓存下的所有数据
  36. void Clear();
  37. Task ClearAsync();
  38. }

强类型缓存

CacheExtensions是ICache的扩展.

  1. public static class CacheExtensions
  2. {
  3. // 其他代码
  4. // 转换强类型缓存
  5. public static ITypedCache<TKey, TValue> AsTyped<TKey, TValue>(this ICache cache)
  6. {
  7. return new TypedCacheWrapper<TKey, TValue>(cache);
  8. }
  9. // 其他代码
  10. }

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

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

  1. public class TypedCacheWrapper<TKey, TValue> : ITypedCache<TKey, TValue>
  2. {
  3. // 具体调用AsTyped这个静态方法的Icache对象
  4. public ICache InternalCache { get; private set; }
  5. public TypedCacheWrapper(ICache internalCache)
  6. {
  7. InternalCache = internalCache;
  8. }
  9. // 缓存名字
  10. public string Name
  11. {
  12. get { return InternalCache.Name; }
  13. }
  14. // 滑动过期时间
  15. public TimeSpan DefaultSlidingExpireTime
  16. {
  17. get { return InternalCache.DefaultSlidingExpireTime; }
  18. set { InternalCache.DefaultSlidingExpireTime = value; }
  19. }
  20. // 绝对过期时间
  21. public TimeSpan? DefaultAbsoluteExpireTime
  22. {
  23. get { return InternalCache.DefaultAbsoluteExpireTime; }
  24. set { InternalCache.DefaultAbsoluteExpireTime = value; }
  25. }
  26. // 释放
  27. public void Dispose()
  28. {
  29. InternalCache.Dispose();
  30. }
  31. // 清空
  32. public void Clear()
  33. {
  34. InternalCache.Clear();
  35. }
  36. public Task ClearAsync()
  37. {
  38. return InternalCache.ClearAsync();
  39. }
  40. // 取 删 。。。。 其实调用的还是ICache的扩展方法
  41. // return (TValue)cache.Get(key.ToString(), (k) => (object)factory(key));
  42. // 最后还是做了强转
  43. public TValue Get(TKey key, Func<TKey, TValue> factory)
  44. {
  45. return InternalCache.Get(key, factory);
  46. }
  47. public TValue[] Get(TKey[] keys, Func<TKey, TValue> factory)
  48. {
  49. return InternalCache.Get(keys, factory);
  50. }
  51. public Task<TValue> GetAsync(TKey key, Func<TKey, Task<TValue>> factory)
  52. {
  53. return InternalCache.GetAsync(key, factory);
  54. }
  55. public Task<TValue[]> GetAsync(TKey[] keys, Func<TKey, Task<TValue>> factory)
  56. {
  57. return InternalCache.GetAsync(keys, factory);
  58. }
  59. public TValue GetOrDefault(TKey key)
  60. {
  61. return InternalCache.GetOrDefault<TKey, TValue>(key);
  62. }
  63. public TValue[] GetOrDefault(TKey[] keys)
  64. {
  65. return InternalCache.GetOrDefault<TKey, TValue>(keys);
  66. }
  67. public Task<TValue> GetOrDefaultAsync(TKey key)
  68. {
  69. return InternalCache.GetOrDefaultAsync<TKey, TValue>(key);
  70. }
  71. public Task<TValue[]> GetOrDefaultAsync(TKey[] keys)
  72. {
  73. return InternalCache.GetOrDefaultAsync<TKey, TValue>(keys);
  74. }
  75. public void Set(TKey key, TValue value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
  76. {
  77. InternalCache.Set(key.ToString(), value, slidingExpireTime, absoluteExpireTime);
  78. }
  79. public void Set(KeyValuePair<TKey, TValue>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
  80. {
  81. var stringPairs = pairs.Select(p => new KeyValuePair<string, object>(p.Key.ToString(), p.Value));
  82. InternalCache.Set(stringPairs.ToArray(), slidingExpireTime, absoluteExpireTime);
  83. }
  84. public Task SetAsync(TKey key, TValue value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
  85. {
  86. return InternalCache.SetAsync(key.ToString(), value, slidingExpireTime, absoluteExpireTime);
  87. }
  88. public Task SetAsync(KeyValuePair<TKey, TValue>[] pairs, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
  89. {
  90. var stringPairs = pairs.Select(p => new KeyValuePair<string, object>(p.Key.ToString(), p.Value));
  91. return InternalCache.SetAsync(stringPairs.ToArray(), slidingExpireTime, absoluteExpireTime);
  92. }
  93. public void Remove(TKey key)
  94. {
  95. InternalCache.Remove(key.ToString());
  96. }
  97. public void Remove(TKey[] keys)
  98. {
  99. InternalCache.Remove(keys.Select(key => key.ToString()).ToArray());
  100. }
  101. public Task RemoveAsync(TKey key)
  102. {
  103. return InternalCache.RemoveAsync(key.ToString());
  104. }
  105. public Task RemoveAsync(TKey[] keys)
  106. {
  107. return InternalCache.RemoveAsync(keys.Select(key => key.ToString()).ToArray());
  108. }
  109. }

ICachingConfiguration

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

  1. public virtual void Initialize()
  2. {
  3. IocManager.IocContainer.Install(new AbpCoreInstaller());
  4. }
  5. internal class AbpCoreInstaller : IWindsorInstaller
  6. {
  7. public void Install(IWindsorContainer container, IConfigurationStore store)
  8. {
  9. container.Register(
  10. // 其他配置组建(略)..
  11. Component.For<ICachingConfiguration, CachingConfiguration>().ImplementedBy<CachingConfiguration>().LifestyleSingleton()
  12. );
  13. }
  14. }

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

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

在来看看CachingConfiguration

  1. internal class CachingConfiguration : ICachingConfiguration
  2. {
  3. public IAbpStartupConfiguration AbpConfiguration { get; private set; }
  4. // 缓存配置器集合
  5. private readonly List<ICacheConfigurator> _configurators;
  6. public IReadOnlyList<ICacheConfigurator> Configurators
  7. {
  8. get { return _configurators.ToImmutableList(); }
  9. }
  10. // ctor
  11. public CachingConfiguration(IAbpStartupConfiguration abpConfiguration)
  12. {
  13. AbpConfiguration = abpConfiguration;
  14. _configurators = new List<ICacheConfigurator>();
  15. }
  16. // 为所有缓存设置 一些配置.
  17. public void ConfigureAll(Action<ICache> initAction)
  18. {
  19. _configurators.Add(new CacheConfigurator(initAction));
  20. }
  21. // 为指定名称的缓存 设置一些配置。
  22. public void Configure(string cacheName, Action<ICache> initAction)
  23. {
  24. _configurators.Add(new CacheConfigurator(cacheName, initAction));
  25. }
  26. }
  1. internal class CacheConfigurator : ICacheConfigurator
  2. {
  3. // 缓存名字
  4. public string CacheName { get; private set; }
  5. // 执行的配置操作
  6. public Action<ICache> InitAction { get; private set; }
  7. public CacheConfigurator(Action<ICache> initAction)
  8. {
  9. InitAction = initAction;
  10. }
  11. public CacheConfigurator(string cacheName, Action<ICache> initAction)
  12. {
  13. CacheName = cacheName;
  14. InitAction = initAction;
  15. }
  16. }

在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可以独自扩展

ABP缓存的更多相关文章

  1. 基于DDD的.NET开发框架 - ABP缓存Caching实现

    返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应 ...

  2. ABP缓存示例

    private readonly ICacheManager _cacheManager; public ProgrammeManage(ICacheManager cacheManager) { _ ...

  3. ABP框架 - 缓存

    文档目录 本节内容: 简介 ICacheManager ICache ITypedCache 配置 实体缓存 EntityCache 是如何工作 Redis 缓存集成 简介 ABP提供了一个缓存接口, ...

  4. ABP入门系列(13)——Redis缓存用起来

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 创建任务时我们需要指定分配给谁,Demo中我们使用一个下拉列表用来显示当前系统的所有用 ...

  5. ABP官方文档翻译 2.3 缓存

    缓存 介绍 ICacheManager 警告:GetCache方法 ICache ITypedCache 配置 实体缓存 实体缓存如何工作 Redis缓存集成 介绍 ABP为缓存提供了一个抽象接口,它 ...

  6. ABP框架 - 缓存( 转)

    出处:http://www.cnblogs.com/kid1412/p/5987083.html 文档目录 本节内容: 简介 ICacheManager ICache ITypedCache 配置 实 ...

  7. ABP开发框架前后端开发系列---(15)ABP框架的服务端和客户端缓存的使用

    缓存在一个大型一点的系统里面是必然会涉及到的,合理的使用缓存能够给我们的系统带来更高的响应速度.由于数据提供服务涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发 ...

  8. 一步一步学习ABP项目系列文章目录

    1.概述 基于DDD的.NET开发框架 - ABP初探 基于DDD的.NET开发框架 - ABP分层设计 基于DDD的.NET开发框架 - ABP模块设计 基于DDD的.NET开发框架 - ABP启动 ...

  9. Redis缓存用起来

    Redis缓存用起来 1. 引言 创建任务时我们需要指定分配给谁,Demo中我们使用一个下拉列表用来显示当前系统的所有用户,以供用户选择.我们每创建一个任务时都要去数据库取一次用户列表,然后绑定到用户 ...

随机推荐

  1. JavaScript中有时候需要获取当前的时间戳

    JavaScript中有时候需要获取当前的时间戳信息,下面列举了三种获取当前时间戳的方法,第一种方法只精确到秒,后两种方法精确到毫秒. 第一种方法 var timestamp1 = Date.pars ...

  2. BZOJ2878 [Noi2012]迷失游乐园

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  3. network namespace连接的4种方法及性能

    veth pair # add the namespaces ip netns add ns1 ip netns add ns2 # create the veth pair ip link add ...

  4. Spring Boot入门——freemarker

    使用步骤: 1.在pom.xml中添加相关依赖 <!-- 添加freemarker依赖 --> <dependency> <groupId>org.springfr ...

  5. BZOJ 2425 [HAOI2010]计数:数位dp + 组合数

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2425 题意: 给你一个数字n,长度不超过50. 你可以将这个数字: (1)去掉若干个0 ( ...

  6. 使用BeanUtils方法拷贝不上问题

    最近在项目中,发现BeanUtils.copyProperties方法拷贝bean属性时候,有的时候会失效.最后发现是由于项目中引用了spring和common两个包,都有BeanUtils方法,错误 ...

  7. python基础4 - 判断(if)语句

    6. 判断(if)语句 6.1 if 判断语句基本语法 在 Python 中,if 语句 就是用来进行判断的,格式如下: if 要判断的条件: 条件成立时,要做的事情 …… 注意:代码的缩进为一个 t ...

  8. 配置web项目出的各种error (安装sql2008错误,网站连接数据库error错误等等)

      一个破error:40 错误搞出了很多莫名其妙的为问题,搞了5天,最后重装系统加上重新配置终于好了. 1. 关于SQL 2008 安装错误 安装之前必须安装VS2008 SP1 安装到最后提示 试 ...

  9. linux查看网卡速度

    ethtool eth0 会包含速度模式等各项属性信息   lspci|grep -i ether 可以查看硬件设备具体型号,会包含硬件厂商及信息   dmesg |grep -i eth 会显示系统 ...

  10. Linux 性能监控分析

    好文,参考 http://blog.csdn.net/hexieshangwang/article/details/47187185