介紹
此系列文章主要是對ABP源碼進行解讀甫窟,初探作者在創(chuàng)造ABP的框架思路籽前,和使用到的設計模式進行。
通過解讀ABP源碼付燥,可以提升ABP使用方式宣谈,可以提升編碼意識,提高面向對象編程思想键科。
本篇文章主要介紹ABP框架的緩存實現(xiàn)機制闻丑。
UML
- ICache:定義一個可以存儲并通過鍵獲取項目的緩存
- CacheBase:基類緩存,簡單實現(xiàn)
ICache
- AbpMemoryCache:使用
MemoryCache
實現(xiàn)ICache
- ICacheManager:緩存管理器應該,單例對象勋颖,跟蹤和管理緩存對象
- CacheManagerBase:緩存管理器的基類
- AbpMemoryCacheManager:使用
MemoryCache
實現(xiàn)ICacheManager
- ICacheConfigurator:緩存配置器
- CacheConfigurator:實現(xiàn)
ICacheConfigurator
- ICachingConfiguration:緩存系統(tǒng)配置
- CachingConfiguration:實現(xiàn)
ICachingConfiguration
源碼解析
ICache
ICache主要是定義一個緩存項目接口嗦嗡,并且提供超時時間、獲取值牙言、設置緩存等內容酸钦。
ABP系統(tǒng)默認系統(tǒng)了四個項目:應用程式設置緩存、租戶設置緩存咱枉、用戶設置緩存卑硫、多語言腳本緩存
/// <summary>
/// Defines a cache that can be store and get items by keys.
/// 定義一個可以存儲并通過鍵獲取項目的緩存
/// </summary>
public interface ICache : IDisposable
{
/// <summary>
/// Unique name of the cache.
/// 緩存唯一的名稱
/// </summary>
string Name { get; }
/// <summary>
/// Default sliding expire time of cache items.
/// Default value: 60 minutes (1 hour).
/// Can be changed by configuration.
/// 默認緩存過期時間
/// 默認值是1小時
/// 可以通過配置改變
/// </summary>
TimeSpan DefaultSlidingExpireTime { get; set; }
/// <summary>
/// Default absolute expire time of cache items.
/// Default value: null (not used).
/// 默認的緩存項的絕對過期時間
/// 默認值:null(沒有使用)
/// </summary>
TimeSpan? DefaultAbsoluteExpireTime { get; set; }
/// <summary>
/// Gets an item from the cache.
/// This method hides cache provider failures (and logs them),
/// uses the factory method to get the object if cache provider fails.
/// 從緩存中獲取一個項目
/// 這個方法隱藏了緩存提供者失敗信息(并記錄它們),如果緩存提供者失敗蚕断,則使用工廠方法來獲取對象
/// </summary>
/// <param name="key">Key</param>
/// <param name="factory">Factory method to create cache item if not exists
/// 如果不存在的話欢伏,創(chuàng)建緩存項的工廠方法
/// </param>
/// <returns>Cached item</returns>
object Get(string key, Func<string, object> factory);
/// <summary>
/// Gets an item from the cache.
/// This method hides cache provider failures (and logs them),
/// uses the factory method to get the object if cache provider fails.
/// </summary>
/// <param name="key">Key</param>
/// <param name="factory">Factory method to create cache item if not exists</param>
/// <returns>Cached item</returns>
Task<object> GetAsync(string key, Func<string, Task<object>> factory);
/// <summary>
/// Gets an item from the cache or null if not found.
/// 從緩存中獲取一個項目,如果沒有找到亿乳,則可以獲得null
/// </summary>
/// <param name="key">Key</param>
/// <returns>Cached item or null if not found</returns>
object GetOrDefault(string key);
/// <summary>
/// Gets an item from the cache or null if not found.
/// </summary>
/// <param name="key">Key</param>
/// <returns>Cached item or null if not found</returns>
Task<object> GetOrDefaultAsync(string key);
/// <summary>
/// Saves/Overrides an item in the cache by a key.
/// Use one of the expire times at most (<paramref name="slidingExpireTime"/> or <paramref name="absoluteExpireTime"/>).
/// If none of them is specified, then
/// <see cref="DefaultAbsoluteExpireTime"/> will be used if it's not null. Othewise, <see cref="DefaultSlidingExpireTime"/>
/// will be used.
/// 在緩存中通過一個鍵來覆蓋一個條目
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
/// <param name="slidingExpireTime">Sliding expire time</param>
/// <param name="absoluteExpireTime">Absolute expire time</param>
void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
/// <summary>
/// Saves/Overrides an item in the cache by a key.
/// Use one of the expire times at most (<paramref name="slidingExpireTime"/> or <paramref name="absoluteExpireTime"/>).
/// If none of them is specified, then
/// <see cref="DefaultAbsoluteExpireTime"/> will be used if it's not null. Othewise, <see cref="DefaultSlidingExpireTime"/>
/// will be used.
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
/// <param name="slidingExpireTime">Sliding expire time</param>
/// <param name="absoluteExpireTime">Absolute expire time</param>
Task SetAsync(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
/// <summary>
/// Removes a cache item by it's key.
/// 通過它的鍵刪除緩存項
/// </summary>
/// <param name="key">Key</param>
void Remove(string key);
/// <summary>
/// Removes a cache item by it's key (does nothing if given key does not exists in the cache).
/// </summary>
/// <param name="key">Key</param>
Task RemoveAsync(string key);
/// <summary>
/// Clears all items in this cache.
/// 清除緩存中的所有項
/// </summary>
void Clear();
/// <summary>
/// Clears all items in this cache.
/// </summary>
Task ClearAsync();
}
CacheBase
緩存項目基類只要實現(xiàn)了基本的存取操作硝拧,但是具體的實現(xiàn),下沉到子類實現(xiàn)
/// <summary>
/// Base class for caches.
/// It's used to simplify implementing <see cref="ICache"/>.
/// 基類緩存
/// 簡單實現(xiàn)<see cref="ICache"/>
/// </summary>
public abstract class CacheBase : ICache
{
public ILogger Logger { get; set; }
public string Name { get; }
public TimeSpan DefaultSlidingExpireTime { get; set; }
public TimeSpan? DefaultAbsoluteExpireTime { get; set; }
protected readonly object SyncObj = new object();
private readonly AsyncLock _asyncLock = new AsyncLock();
/// <summary>
/// Constructor.
/// </summary>
/// <param name="name"></param>
protected CacheBase(string name)
{
Name = name;
DefaultSlidingExpireTime = TimeSpan.FromHours(1);
Logger = NullLogger.Instance;
}
public virtual object Get(string key, Func<string, object> factory)
{
object item = null;
try
{
item = GetOrDefault(key);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (item == null)
{
lock (SyncObj)
{
try
{
item = GetOrDefault(key);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (item == null)
{
item = factory(key);
if (item == null)
{
return null;
}
try
{
Set(key, item);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
}
}
}
return item;
}
public virtual async Task<object> GetAsync(string key, Func<string, Task<object>> factory)
{
object item = null;
try
{
item = await GetOrDefaultAsync(key);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (item == null)
{
using (await _asyncLock.LockAsync())
{
try
{
item = await GetOrDefaultAsync(key);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (item == null)
{
item = await factory(key);
if (item == null)
{
return null;
}
try
{
await SetAsync(key, item);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
}
}
}
return item;
}
public abstract object GetOrDefault(string key);
public virtual Task<object> GetOrDefaultAsync(string key)
{
return Task.FromResult(GetOrDefault(key));
}
public abstract void Set(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null);
public virtual Task SetAsync(string key, object value, TimeSpan? slidingExpireTime = null, TimeSpan? absoluteExpireTime = null)
{
Set(key, value, slidingExpireTime);
return Task.FromResult(0);
}
public abstract void Remove(string key);
public virtual Task RemoveAsync(string key)
{
Remove(key);
return Task.FromResult(0);
}
public abstract void Clear();
public virtual Task ClearAsync()
{
Clear();
return Task.FromResult(0);
}
public virtual void Dispose()
{
}
}
AbpMemoryCache
AbpMemoryCache
是基于MemoryCache
實現(xiàn) ICache
葛假,使用具體的緩存技術實現(xiàn)緩存項目
/// <summary>
/// Implements <see cref="ICache"/> to work with <see cref="MemoryCache"/>.
/// 使用<see cref="MemoryCache"/> 實現(xiàn) <see cref="ICache"/>
/// </summary>
public class AbpMemoryCache : CacheBase
{
private MemoryCache _memoryCache;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="name">Unique name of the cache</param>
public AbpMemoryCache(string name)
: base(name)
{
_memoryCache = new MemoryCache(new OptionsWrapper<MemoryCacheOptions>(new MemoryCacheOptions()));
}
public override object GetOrDefault(string key)
{
return _memoryCache.Get(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);
}
}
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();
}
}
ICacheManager
緩存管理器應該障陶,單例對象,跟蹤和管理緩存對象
/// <summary>
/// An upper level container for <see cref="ICache"/> objects.
/// A cache manager should work as Singleton and track and manage <see cref="ICache"/> objects.
/// 緩存管理器應該聊训,單例對象抱究,跟蹤和管理緩存對象
/// </summary>
public interface ICacheManager : IDisposable
{
/// <summary>
/// Gets all caches.
/// 獲取所有緩存
/// </summary>
/// <returns>List of caches</returns>
IReadOnlyList<ICache> GetAllCaches();
/// <summary>
/// Gets a <see cref="ICache"/> instance.
/// It may create the cache if it does not already exists.
/// 獲取緩存實例
/// 如果緩存不存在,則創(chuàng)建緩存
/// </summary>
/// <param name="name">
/// Unique and case sensitive name of the cache.
/// 緩存的唯一的名稱带斑,大小寫敏感
/// </param>
/// <returns>The cache reference</returns>
[NotNull] ICache GetCache([NotNull] string name);
}
CacheManagerBase
緩存管理器的基類鼓寺,實現(xiàn)基本的操作勋拟,將具體的算法下層到子類實現(xiàn)
/// <summary>
/// Base class for cache managers.
/// 緩存管理器的基類
/// </summary>
public abstract class CacheManagerBase : ICacheManager, ISingletonDependency
{
protected readonly IIocManager IocManager;
protected readonly ICachingConfiguration Configuration;
protected readonly ConcurrentDictionary<string, ICache> Caches;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="iocManager"></param>
/// <param name="configuration"></param>
protected CacheManagerBase(IIocManager iocManager, ICachingConfiguration configuration)
{
IocManager = iocManager;
Configuration = configuration;
Caches = new ConcurrentDictionary<string, ICache>();
}
public IReadOnlyList<ICache> GetAllCaches()
{
return Caches.Values.ToImmutableList();
}
public virtual ICache GetCache(string name)
{
Check.NotNull(name, nameof(name));
return Caches.GetOrAdd(name, (cacheName) =>
{
var cache = CreateCacheImplementation(cacheName);
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();
}
protected virtual void DisposeCaches()
{
foreach (var cache in Caches)
{
IocManager.Release(cache.Value);
}
}
/// <summary>
/// Used to create actual cache implementation.
/// 用于創(chuàng)建實際的緩存實現(xiàn)
/// </summary>
/// <param name="name">Name of the cache</param>
/// <returns>Cache object</returns>
protected abstract ICache CreateCacheImplementation(string name);
}
AbpMemoryCacheManager
使用MemoryCache
實現(xiàn)的ICacheManager
,使用具體的緩存組件實現(xiàn)ICacheManager妈候,實現(xiàn)父類CacheManagerBase
的方法
/// <summary>
/// Implements <see cref="ICacheManager"/> to work with MemoryCache.
/// 使用MemoryCache實現(xiàn)<see cref="ICacheManager"/>
/// </summary>
public class AbpMemoryCacheManager : CacheManagerBase
{
public ILogger Logger { get; set; }
/// <summary>
/// Constructor.
/// </summary>
public AbpMemoryCacheManager(IIocManager iocManager, ICachingConfiguration configuration)
: base(iocManager, configuration)
{
Logger = NullLogger.Instance;
}
protected override ICache CreateCacheImplementation(string name)
{
return new AbpMemoryCache(name)
{
Logger = Logger
};
}
protected override void DisposeCaches()
{
foreach (var cache in Caches.Values)
{
cache.Dispose();
}
}
}
ICacheConfigurator
緩存配置器敢靡,配置單個緩存項目,主要是配置創(chuàng)建之后的調用方法
/// <summary>
/// A registered cache configurator.
/// 緩存配置器
/// </summary>
public interface ICacheConfigurator
{
/// <summary>
/// Name of the cache.
/// It will be null if this configurator configures all caches.
/// 緩存名稱苦银,如果這個配置器配置了所有的緩存啸胧,它就會是null
/// </summary>
string CacheName { get; }
/// <summary>
/// Configuration action. Called just after the cache is created.
/// 配置操作。在緩存創(chuàng)建之后調用
/// </summary>
Action<ICache> InitAction { get; }
}
ICachingConfiguration
緩存系統(tǒng)配置幔虏,配置多個ICache信息
/// <summary>
/// Used to configure caching system.
/// 緩存系統(tǒng)配置
/// </summary>
public interface ICachingConfiguration
{
/// <summary>
/// Gets the ABP configuration object.
/// ABP配置值系統(tǒng)
/// </summary>
IAbpStartupConfiguration AbpConfiguration { get; }
/// <summary>
/// List of all registered configurators.
/// 所有已注冊的配置器列表
/// </summary>
IReadOnlyList<ICacheConfigurator> Configurators { get; }
/// <summary>
/// Used to configure all caches.
/// 用于配置所有緩存
/// </summary>
/// <param name="initAction">
/// An action to configure caches
/// This action is called for each cache just after created.
/// 配置緩存的操作
/// 這個動作在創(chuàng)建后的每個緩存中都被調用
/// </param>
void ConfigureAll(Action<ICache> initAction);
/// <summary>
/// Used to configure a specific cache.
/// 用于配置特定的緩存
/// </summary>
/// <param name="cacheName">Cache name</param>
/// <param name="initAction">
/// An action to configure the cache.
/// This action is called just after the cache is created.
/// </param>
void Configure(string cacheName, Action<ICache> initAction);
}
設計模式
- 模板方法模式:
ICacheManager
,CacheManagerBase
,AbpMemoryCacheManager
吓揪,父類實現(xiàn)主要算法,定義調用順序和過程所计,子類實現(xiàn)具體算法 - 橋接模式:
ICacheManager
,ICache
獨立變化Manager和Cache,是的Manager和Cache可以獨自擴展