ABP緩存

簡介

緩存是作什麼的?
簡單的能夠認爲是一個鍵值對的數據存於內存中,高速讀取。做用爲了減小和數據庫的交互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能夠獨自擴展

相關文章
相關標籤/搜索