227 lines
6.5 KiB
C#
227 lines
6.5 KiB
C#
namespace MiaoYu.Core.Redis.Aop.Cache;
|
|
|
|
/// <summary>
|
|
/// 清除缓存AOP
|
|
/// </summary>
|
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
|
public class CacheEvictAttribute : BaseCacheAttribute
|
|
{
|
|
private readonly Type _cacheClassType;
|
|
private readonly string _actionName;
|
|
|
|
public CacheEvictAttribute()
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用于设置 默认 缓存key 需要 ,自动组合默认缓存名称
|
|
/// </summary>
|
|
/// <param name="cacheClassType">缓存 类 类型</param>
|
|
/// <param name="actionName">缓存函数名称</param>
|
|
public CacheEvictAttribute(Type cacheClassType, string actionName)
|
|
{
|
|
_cacheClassType = cacheClassType;
|
|
_actionName = actionName;
|
|
}
|
|
|
|
protected override string GetCacheKey(MethodContext context)
|
|
{
|
|
if (_cacheClassType != null && !string.IsNullOrWhiteSpace(_actionName))
|
|
{
|
|
return _cacheClassType?.FullName + "." + _actionName;
|
|
}
|
|
|
|
return base.GetCacheKey(context);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除时机 默认方法执行完
|
|
/// </summary>
|
|
/// <value></value>
|
|
public bool BeforeRun { get; set; } = false;
|
|
|
|
|
|
public override void OnEntry(MethodContext context)
|
|
{
|
|
if (BeforeRun)
|
|
{
|
|
RemoveKey(context);
|
|
}
|
|
}
|
|
|
|
public override void OnException(MethodContext context)
|
|
{
|
|
|
|
}
|
|
|
|
public override void OnSuccess(MethodContext context)
|
|
{
|
|
|
|
}
|
|
|
|
public override void OnExit(MethodContext context)
|
|
{
|
|
if (!BeforeRun)
|
|
{
|
|
RemoveKey(context);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除key
|
|
/// </summary>
|
|
/// <param name="aopContext"></param>
|
|
private void RemoveKey(MethodContext aopContext)
|
|
{
|
|
if (RedisServiceType == null)
|
|
{
|
|
RemoveMemoryKey(aopContext);
|
|
}
|
|
else
|
|
{
|
|
RemoveRedisKey(aopContext);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除redis key
|
|
/// </summary>
|
|
/// <param name="aopContext"></param>
|
|
private void RemoveRedisKey(MethodContext aopContext)
|
|
{
|
|
var cacheKey = GetCacheKey(aopContext);
|
|
if (cacheKey.Contains('*'))
|
|
{
|
|
RemoveRedisGroupKey(aopContext, cacheKey);
|
|
}
|
|
else
|
|
{
|
|
var redisCache = GetDatabase(aopContext);
|
|
redisCache.KeyDelete(cacheKey);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除Redis分组的key
|
|
/// </summary>
|
|
/// <param name="aopContext"></param>
|
|
/// <param name="cacheKey"></param>
|
|
private void RemoveRedisGroupKey(MethodContext aopContext, string cacheKey)
|
|
{
|
|
var redisMultiplexer = GetMultiplexer(aopContext);
|
|
List<RedisKey> redisKeys = new List<RedisKey>();
|
|
var endPoints = redisMultiplexer.GetEndPoints();
|
|
foreach (var endPoint in endPoints)
|
|
{
|
|
var server = redisMultiplexer.GetServer(endPoint);
|
|
foreach (var key in server.Keys(pattern: cacheKey))
|
|
{
|
|
redisKeys.Add(key);
|
|
}
|
|
}
|
|
|
|
var redisCache = GetDatabase(aopContext);
|
|
redisCache.KeyDelete(redisKeys.ToArray());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除内存key
|
|
/// </summary>
|
|
/// <param name="aopContext"></param>
|
|
private void RemoveMemoryKey(MethodContext aopContext)
|
|
{
|
|
var cacheKey = GetCacheKey(aopContext);
|
|
var cache = this.GetService<IMemoryCache>(aopContext);
|
|
|
|
// 是否要进行前缀或后缀匹配
|
|
if (cacheKey.StartsWith('*'))
|
|
{
|
|
var pattern = cacheKey.Substring(1, cacheKey.Length - 1);
|
|
RemoveMemoryGroupKey(pattern, cache, false);
|
|
}
|
|
else if (cacheKey.EndsWith('*'))
|
|
{
|
|
var pattern = cacheKey.Substring(0, cacheKey.Length - 1);
|
|
RemoveMemoryGroupKey(pattern, cache, true);
|
|
}
|
|
else
|
|
{
|
|
cache.Remove(cacheKey);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除内存缓存分组的 key
|
|
/// </summary>
|
|
/// <param name="pattern"></param>
|
|
/// <param name="memoryCache"></param>
|
|
/// <param name="isStart"></param>
|
|
private void RemoveMemoryGroupKey(string pattern, IMemoryCache memoryCache, bool isStart)
|
|
{
|
|
var entries = memoryCache.GetType().GetField("_entries", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(memoryCache) as IDictionary;
|
|
if (entries != null)
|
|
{
|
|
List<string> keys = new List<string>();
|
|
|
|
if (isStart)
|
|
{
|
|
// 前缀模式匹配
|
|
foreach (var key in entries.Keys)
|
|
{
|
|
var k = key as string;
|
|
if (k != null)
|
|
{
|
|
if (k.StartsWith(pattern))
|
|
{
|
|
keys.Add(k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 尾缀模式匹配
|
|
foreach (var key in entries.Keys)
|
|
{
|
|
var k = key as string;
|
|
if (k != null)
|
|
{
|
|
if (k.EndsWith(pattern))
|
|
{
|
|
keys.Add(k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var key in keys)
|
|
{
|
|
memoryCache.Remove(key);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("前缀或尾缀匹配不可用!");
|
|
}
|
|
}
|
|
|
|
private IConnectionMultiplexer GetMultiplexer(MethodContext aopContext)
|
|
{
|
|
var redisService = this.GetService(aopContext, RedisServiceType);
|
|
var propertyInfos = redisService.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
|
|
var databasePropertyInfo = propertyInfos.FirstOrDefault(w => w.PropertyType == typeof(IConnectionMultiplexer));
|
|
if (databasePropertyInfo == null)
|
|
{
|
|
throw new Exception($"Redis服务 {RedisServiceType.FullName} 找不到属性 public IConnectionMultiplexer {nameof(IConnectionMultiplexer)} {{get;}}");
|
|
}
|
|
// 获取 idatabase
|
|
var redisCache = (IConnectionMultiplexer)databasePropertyInfo.GetValue(redisService);
|
|
if (redisCache == null)
|
|
{
|
|
throw new Exception($"Redis服务 {RedisServiceType.FullName} 属性 public IConnectionMultiplexer {nameof(IConnectionMultiplexer)} {{get;}} 是 null ");
|
|
}
|
|
|
|
return redisCache;
|
|
}
|
|
} |