namespace MiaoYu.Core.Redis.Aop.Cache; /// /// 清除缓存AOP /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class CacheEvictAttribute : BaseCacheAttribute { private readonly Type _cacheClassType; private readonly string _actionName; public CacheEvictAttribute() { } /// /// 用于设置 默认 缓存key 需要 ,自动组合默认缓存名称 /// /// 缓存 类 类型 /// 缓存函数名称 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); } /// /// 移除时机 默认方法执行完 /// /// 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); } } /// /// 移除key /// /// private void RemoveKey(MethodContext aopContext) { if (RedisServiceType == null) { RemoveMemoryKey(aopContext); } else { RemoveRedisKey(aopContext); } } /// /// 移除redis key /// /// private void RemoveRedisKey(MethodContext aopContext) { var cacheKey = GetCacheKey(aopContext); if (cacheKey.Contains('*')) { RemoveRedisGroupKey(aopContext, cacheKey); } else { var redisCache = GetDatabase(aopContext); redisCache.KeyDelete(cacheKey); } } /// /// 移除Redis分组的key /// /// /// private void RemoveRedisGroupKey(MethodContext aopContext, string cacheKey) { var redisMultiplexer = GetMultiplexer(aopContext); List redisKeys = new List(); 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()); } /// /// 移除内存key /// /// private void RemoveMemoryKey(MethodContext aopContext) { var cacheKey = GetCacheKey(aopContext); var cache = this.GetService(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); } } /// /// 移除内存缓存分组的 key /// /// /// /// 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 keys = new List(); 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; } }