第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5426字,纯文字阅读大概需要8分钟。
内容图文
上一讲主要是说如何将数据集存储到redis服务器里,而今天主要说的是缓存里的键名,我们习惯叫它key.
redis或者其它缓存组件实现的存储机制里,它将很多方法对应的数据集存储在一个公共的空间里,这个空间足够大,当然它也是共享的,没有具体的分区,也就是说,如果你的key重复了,那这事就有点坏味道了,对于一个项目肯定没什么问题,只要做到方法名不相同就可以,但是,如果是多个项目共享一个缓存服务器(缓存中间件,这是很正常的,没有什么公司一个项目对应一个缓存服务器,没必要,当你的项目足够大时,可以会有分模块去做缓存服务器的概念),今天的重点就是在拦截组件中优化我们的key,对于get和put,remove方法都要进行优化.
/// <summary> /// 表示用于方法缓存功能的拦截行为。 /// </summary> public class CachingBehavior : IInterceptionBehavior { /// <summary> /// 缓存项目名称,每个项目有自己的名称 /// 避免缓存键名重复 /// </summary> static readonly string cacheProjectName = System.Configuration.ConfigurationManager.AppSettings["CacheProjectName"] ?? "DataSetCache"; #region Private Methods ///<summary>/// 根据指定的<see cref="CachingAttribute"/>以及<see cref="IMethodInvocation"/>实例, /// 获取与某一特定参数值相关的键名。 ///</summary>///<param name="cachingAttribute"><see cref="CachingAttribute"/>实例。</param>///<param name="input"><see cref="IMethodInvocation"/>实例。</param>///<returns>与某一特定参数值相关的键名。</returns>privatestring GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input) { switch (cachingAttribute.Method) { // 如果是Remove,则不存在特定值键名,所有的以该方法名称相关的缓存都需要清除case CachingMethod.Remove: returnnull; // 如果是Get或者Put,则需要产生一个针对特定参数值的键名case CachingMethod.Get: case CachingMethod.Put: if (input.Arguments != null && input.Arguments.Count > 0) { var sb = new StringBuilder(); for (int i = 0; i < input.Arguments.Count; i++) { if (input.Arguments[i].GetType().BaseType == typeof(LambdaExpression))//lambda处理 { var exp = input.Arguments[i] as LambdaExpression; var arr = ((System.Runtime.CompilerServices.Closure)(((System.Delegate)(Expression.Lambda(exp).Compile().DynamicInvoke())).Target)).Constants; Type t = arr[0].GetType(); string result = ""; foreach (var member in t.GetFields()) { result += member.Name + "_" + t.GetField(member.Name).GetValue(arr[0]) + "_"; } result = result.Remove(result.Length - 1); sb.Append(result.ToString()); } elseif (input.Arguments[i].GetType() != typeof(string)//类和结构体处理 && input.Arguments[i].GetType().BaseType.IsClass) { var obj = input.Arguments[i]; Type t = obj.GetType(); string result = ""; foreach (var member in t.GetProperties()) { result += member.Name + "_" + t.GetProperty(member.Name).GetValue(obj) + "_"; } result = result.Remove(result.Length - 1); sb.Append(result.ToString()); } else//简单值类型处理 { sb.Append(input.Arguments[i].ToString()); } if (i != input.Arguments.Count - 1) sb.Append("_"); } return sb.ToString(); } elsereturn"NULL"; default: thrownew InvalidOperationException("无效的缓存方式。"); } } #endregion#region IInterceptionBehavior Members ///<summary>/// 获取当前行为需要拦截的对象类型接口。 ///</summary>///<returns>所有需要拦截的对象类型接口。</returns>public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } ///<summary>/// 通过实现此方法来拦截调用并执行所需的拦截行为。 ///</summary>///<param name="input">调用拦截目标时的输入信息。</param>///<param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>///<returns>从拦截目标获得的返回信息。</returns>public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { var method = input.MethodBase; //键值前缀string prefix = cacheProjectName + "_" + input.Target.ToString() + "_"; //键名,在put和get时使用var key = prefix + method.Name; if (method.IsDefined(typeof(CachingAttribute), false)) { var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[0]; var valKey = GetValueKey(cachingAttribute, input); switch (cachingAttribute.Method) { case CachingMethod.Get: try { if (CacheManager.Instance.Exists(key, valKey)) { var obj = CacheManager.Instance.Get(key, valKey); var arguments = newobject[input.Arguments.Count]; input.Arguments.CopyTo(arguments, 0); returnnew VirtualMethodReturn(input, obj, arguments); } else { var methodReturn = getNext().Invoke(input, getNext); CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue); return methodReturn; } } catch (Exception ex) { returnnew VirtualMethodReturn(input, ex); } case CachingMethod.Put: try { var methodReturn = getNext().Invoke(input, getNext); if (CacheManager.Instance.Exists(key)) { if (cachingAttribute.Force) { CacheManager.Instance.Remove(key); CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue); } else CacheManager.Instance.Put(key, valKey, methodReturn.ReturnValue); } else CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue); return methodReturn; } catch (Exception ex) { returnnew VirtualMethodReturn(input, ex); } case CachingMethod.Remove: try { var removeKeys = cachingAttribute.CorrespondingMethodNames; foreach (var removeKey in removeKeys) { string delKey = prefix + removeKey; if (CacheManager.Instance.Exists(delKey)) CacheManager.Instance.Remove(delKey); } var methodReturn = getNext().Invoke(input, getNext); return methodReturn; } catch (Exception ex) { returnnew VirtualMethodReturn(input, ex); } default: break; } } return getNext().Invoke(input, getNext); } ///<summary>/// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行 /// 某些操作。 ///</summary>publicbool WillExecute { get { returntrue; } } #endregion }
优化后的key的结构为项目前缀_项目命名空间_方法名,这样的设计我想它不会再有重复了,事实上,如果你的项目正规的话,只要有(项目命名空间_方法名)这一层控制就可以做到key值唯一了,而为了避免意外,我们还是加了一个项目前缀CacheProjectName!
我们可以看一下缓存存储时的键名截图
原文:http://www.cnblogs.com/lori/p/4078188.html
内容总结
以上是互联网集市为您收集整理的第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)全部内容,希望文章能够帮你解决第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。