ABP框架 - 缓存

文档目录

 

本节内容:

 

简介

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<PersonCacheItem>
{

}

最后,我们可以为实体创建缓存类:

public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency
{
    public PersonCache(ICacheManager cacheManager, IRepository<Person> 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“作为默认连接字符串,你可以在配置文件里添加连接字符串重写它,例如:

<add name="Abp.Redis.Cache" connectionString="localhost"/>

同样,你可以向appSettings里添加Redis的数据库Id,例如:

<add key="Abp.Redis.Cache.DatabaseId" value="2"/>

不同的数据库Id,在同一服务器上,帮助创建不同的键空间(独立缓存)。

UseRedis方法也有一个重载,用给定的action(行为)直接设置选项值(在配置文件中重写)。

查看更多有关Redis信息及它的配置,请查阅Redis文档

 

提醒:Redis服务器应该安装和运行在ABP里。

posted @ 2016-10-22 12:59 kid1412 阅读(...) 评论(...) 编辑 收藏