ABP之Caching

簡介

ABP提供緩存抽象,默認使用MemoryCache。可是能夠替換成其餘緩存程序,好比 Abp.RedisCache 是使用Redis實現緩存。web

ICacheManager

緩存的主要接口是ICacheManager,咱們可使用它來得到緩存,好比:
redis

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的緩存。緩存名稱區分大小寫,這意味着「MyCache」和「MyCache」是兩個不一樣的緩存。數據庫

ICache

 ICacheManager.GetCache返回一個ICache,緩存是單例的,是在第一次請求被建立,而後老是返回相同的對象。經過這種方式,咱們能夠在不一樣的類(客戶端)中使用相同的名稱共享相同的緩存。緩存

在示例代碼中,咱們看到了ICache.Get的簡單用法,它有兩個參數,安全

  • key:緩存中項的惟一鍵(字符串)。
  • factory:若是沒有具備給定鍵的Item,則調用該Action。工廠方法應該建立並返回實際的Item。若是給定鍵存在於緩存中,則不調用該Action。

ICache接口還具備GetOrDefault、Set、Remove和Clear等方法,全部方法都有異步版本。服務器

ITypedCache

 ICache 接口使用字符串做爲key,object對象做爲value,ITypedCache是ICache的一個包裝器,用於提供類型安全的通用緩存。咱們可使用通用的GetCache擴展方法來得到一個ITypedCache:併發

ITypedCache<int, Item> myCache = _cacheManager.GetCache<int, Item>("MyCache");

咱們還可使用AsTyped擴展方法將現有的ICache實例轉換爲ITypedCache。app

配置

默認的緩存過時時間是60分鐘,若是在60分鐘以內不使用緩存中的Item,它就會被自動從緩存中刪除。咱們能夠爲全部的緩存配置過時時間,也能夠爲特定的緩存配置特定時間。異步

//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獲取實體並但願經過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屬性,由於咱們但願使用AutoMapper將Person實體自動轉換爲PersonCacheItem對象。若是咱們不使用AutoMapper,咱們應該覆蓋EntityCache類的MapToCacheItem方法來手動轉換/映射它。

雖然這不是必需的,但咱們最好給緩存類定義一個接口:

public interface IPersonCache : IEntityCache<PersonCacheItem>
{

}

最後,咱們能夠建立cache類來緩存Person實體:

public class PersonCache : EntityCache<Person, PersonCacheItem>, IPersonCache, ITransientDependency
{
    public PersonCache(ICacheManager cacheManager, IRepository<Person> repository)
        : base(cacheManager, repository)
    {

    }
}

如上所示,咱們的Person緩存已準備好使用! 緩存類能夠是瞬態的(如本例所示),也能夠是單例的。這並不意味着緩存的數據是瞬時的。它老是全局緩存,並在應用程序中以線程安全的方式訪問。

當咱們想獲取一我的的名字時,咱們可使用這我的的Id從緩存中獲取,好比:

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將實體映射到緩存項,IObjectMapper由AutoMapper模塊實現,能夠覆蓋MapToCacheItem方法來手動將實體映射到緩存項。
  • 它使用cache類的FullName做爲緩存名,能夠經過將緩存名傳遞給基本構造函數來更改它。
  • 它是線程安全的。

若是須要更復雜的緩存需求,能夠擴展EntityCache或建立本身的解決方案。

Redis緩存集成

默認的緩存管理器使用內存緩存。若是有多個併發web服務器運行相同的應用程序,則可能會出現問題。在這種狀況下,可能須要一個分佈式/中央緩存服務器,可使用Redis做爲緩存服務器。

首先須要將Abp.RedisCache經過Nuget包安裝到應用程序中,而後須要爲AbpRedisCacheModule添加DependsOn屬性,並在模塊的PreInitialize方法中調用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方法還有一個重載,它採起一個操做來直接設置選項值(這將覆蓋配置文件中的值)。

有關Redis及其配置的更多信息,請參閱Redis文檔: Redis documentation

 注意:應該安裝並運行Redis服務器來使用ABP中的Redis緩存。

相關文章
相關標籤/搜索