码迷,mamicode.com
首页 > 其他好文 > 详细

第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)

时间:2014-11-06 12:36:06      阅读:188      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   io   color   ar   os   使用   

返回目录

上一讲主要是说如何将数据集存储到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>
        private string GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input)
        {
            switch (cachingAttribute.Method)
            {
                // 如果是Remove,则不存在特定值键名,所有的以该方法名称相关的缓存都需要清除
                case CachingMethod.Remove:
                    return null;
                // 如果是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());
                            }
                            else if (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();
                    }
                    else
                        return "NULL";
                default:
                    throw new 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 = new object[input.Arguments.Count];
                                input.Arguments.CopyTo(arguments, 0);
                                return new VirtualMethodReturn(input, obj, arguments);
                            }
                            else
                            {
                                var methodReturn = getNext().Invoke(input, getNext);
                                CacheManager.Instance.Add(key, valKey, methodReturn.ReturnValue);
                                return methodReturn;
                            }
                        }
                        catch (Exception ex)
                        {
                            return new 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)
                        {
                            return new 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)
                        {
                            return new VirtualMethodReturn(input, ex);
                        }
                    default: break;
                }
            }

            return getNext().Invoke(input, getNext);
        }

        /// <summary>
        /// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
        /// 某些操作。
        /// </summary>
        public bool WillExecute
        {
            get { return true; }
        }

        #endregion
    }

优化后的key的结构为项目前缀_项目命名空间_方法名,这样的设计我想它不会再有重复了,事实上,如果你的项目正规的话,只要有(项目命名空间_方法名)这一层控制就可以做到key值唯一了,而为了避免意外,我们还是加了一个项目前缀CacheProjectName!

我们可以看一下缓存存储时的键名截图

bubuko.com,布布扣

返回目录

 

第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)

标签:des   style   blog   http   io   color   ar   os   使用   

原文地址:http://www.cnblogs.com/lori/p/4078188.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!