文档目录
本节内容:
- 简介
- ICacheManager
- ICache
- ITypedCache
- 配置
- 实体缓存
- EntityCache 是如何工作
- Redis 缓存集成
简介
ABP提供了一个缓存接口,它内部使用了这个缓存接口。虽然接口的默认实现是MemoryCache,但可以用任何其它实现的缓存供应器。Abp.RedisCache包用Redis实现了缓存(查看下方的“Redis 缓存集成”)。
ICacheManager
缓存的主要接口是ICacheManager。我们可以注入它并用它获取一个缓存,如:
public class TestAppService : ApplicationService { private readonly ICacheManager _cacheManager; public TestAppService(ICacheManager cacheManager) { _cacheManager = cacheManager; } public Item GetItem(int id) { //Try to get from cache return _cacheManager .GetCache("MyCache") .Get(id.ToString(), () => GetFromDatabase(id)) as Item; } public Item GetFromDatabase(int id) { //... retrieve item from database } }
在此例里,我们注入了ICacheManager,并获得一个名为MyCache的缓存。
警告:GetCache方法
如果你的类不是单例,不要在你构造器里使用GetCache,否则可能会销毁你的缓存。
ICache
ICacheManager.GetCache方法返回一个ICache。一个缓存是单例的(每个缓存名)。第一次请求时创建,然后一直返回同一个缓存对象。所以,我们可以在不同的类(客户端)里用相同的名字共享同一个缓存。
在示例代码里,我们看到了ICache.get方法的简单使用。它有两个参数:
key:字符串,必需,一个缓存项的键。
factory:一个action(行为),在找不到指定key的缓存项时调用,Factory方法应该创建并返回切实的项,如果指定key的缓存已存在,就不调用。
ICache接口也有如GetOrDefault、Set、Remove和Clear等方法。同样也有async版本。
ITypedCache
ICache接口以字符串为key,值是object类型。ITypedCache包装了ICache并提供了类型安全、泛型。我们可用泛型的GetCache扩展方法,获取一个ITypedCache:
ITypedCache<int, Item> myCache = _cacheManager.GetCache<int, Item>("MyCache");
同样,我们也可用AsTyped扩展方法,把一个已存在的ICache实例转换成ITypedCache。
配置
默认缓存超时是60分钟,它可以改。如果你超过60分钟没有使用缓存中的项,会从缓存中自动移除。你可以配置指定的缓存或是全部的缓存。
//Configuration for all caches Configuration.Caching.ConfigureAll(cache => { cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2); }); //Configuration for a specific cache Configuration.Caching.Configure("MyCache", cache => { cache.DefaultSlidingExpireTime = TimeSpan.FromHours(8); });
这段代码应该写在你模块的PreInitialize方法里,用这段代码,MyCache将有8个小时的超时时间,其它的缓存有2个小时。
在第一次创建缓存(在第一次请求)调用你的配置行为。配置不是只有DefaultSlidingExpireTime,由于缓存对象是一个ICache,所以你可以用它的属性和方法,自由的配置和初始化。
实体缓存
虽然ABP缓存系统出于普通的目的,但有一个EntityCache基类,可帮你缓存实体。如果我们通过它们的Id获取的实体,我们可以用这个基类缓存它们,就不用再频繁地从数据库查询。假设我们有如下所示的一个person实体:
public class Person : Entity { public string Name { get; set; } public int Age { get; set; } }
并假设我们已经知道Id,要频繁地获取Name。首先,我们需要创建一个类来缓存项:
[AutoMapFrom(typeof(Person))] public class PersonCacheItem { public string Name { get; set; } }
我们不应该直接在缓存里存储实体,由于缓存可能需要序列化缓存对象,而实体不一定能序列化(尤其有导航属性的实体)。这就是为什么我们创建一个简单(像DTO:数据传输对象)类存储数据。添加AutoMapFrom特性,它可以自动地把Person转换成PersonCacheItem对象。如果我们不使用AutoMapFrom,我们应该为重载EntityCache类的MapToCacheItem方法,手动转换/映射。
虽然不是必需,但我们可能想为我们的缓存类定义一个接口:
public interface IPersonCache : IEntityCache{ }
最后,我们可以为实体创建缓存类:
public class PersonCache : EntityCache, IPersonCache, ITransientDependency { public PersonCache(ICacheManager cacheManager, IRepository repository) : base(cacheManager, repository) { } }
这就是全部代码,我们的Person缓存已经可用。缓存类可以是暂时的(如示例)或单体的,这不是说缓存的数据是暂时的,它始终在你的应用里是全局的并线程安全的。
现在,任何需要Person的Name时,我们可以通过person的Id从缓存获取,使用Person缓存的示例如下:
public class MyPersonService : ITransientDependency { private readonly IPersonCache _personCache; public MyPersonService(IPersonCache personCache) { _personCache = personCache; } public string GetPersonNameById(int id) { return _personCache[id].Name; //alternative: _personCache.Get(id).Name; } }
我们简单地注入IPersonCache,获取缓存项和获取Name属性。
EntityCache 是如何工作
- 在第一个调用里获取从仓储(从数据库)获取实体,然后在接下来的调用里从缓存里获取。
- 如果实体更新或删除后,它自动使缓存失效,所以它将在下一个调用里重新从数据库获取。
- 使用IObjectMapper映射到缓存项,AutoMpper模块实现了IObjectMapper,所以需要AutoMapper模块。你可以重载MapToCacheItem方法,手动映射实体到缓存项。
- 使用缓存类全名作为缓存时的名称,你可以通过传递一个缓存名给基构造器来改变它。
- 是线程安全的。
如果你需要更复杂的缓存技术,你可以扩展EntityCache或创建你自己的解决方案。
Redis 缓存集成
默认缓存管理使用的是内存缓存。所以,如果你有多个并发的Web服务器使用同个应用,可能会成为一个问题,在这种情况下,你需要一个分布/集中缓存服务,你就可以简单的使用Redis做为你的缓存服务器。
首先,你要在你的应用里,安装Abp.RedisCache的Nuget包(例如,你可在你的Web项目里安装)。接着为AbpRedisCacheModule添加DependsOn特性,然后在你模块预初始化方法里调用useRedis扩展方法。如下所示:
//...other namespaces using Abp.Runtime.Caching.Redis; namespace MyProject.AbpZeroTemplate.Web { [DependsOn( //...other module dependencies typeof(AbpRedisCacheModule))] public class MyProjectWebModule : AbpModule { public override void PreInitialize() { //...other configurations Configuration.Caching.UseRedis(); } //...other code } }
Abp.RedisCache包使用”localhost“作为默认连接字符串,你可以在配置文件里添加连接字符串重写它,例如:
"Abp.Redis.Cache" connectionString="localhost"/>
同样,你可以向appSettings里添加Redis的数据库Id,例如:
"Abp.Redis.Cache.DatabaseId" value="2"/>
不同的数据库Id,在同一服务器上,帮助创建不同的键空间(独立缓存)。
UseRedis方法也有一个重载,用给定的action(行为)直接设置选项值(在配置文件中重写)。
查看更多有关Redis信息及它的配置,请查阅Redis文档。
提醒:Redis服务器应该安装和运行在ABP里。