zoukankan      html  css  js  c++  java
  • AOP缓存实现

    输入参数索引作为缓存键的实现

    using MJD.Framework.CrossCutting;
    using MJD.Framework.ICache;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace MJD.Framework.Aop.Cache
    {
        /// <summary>
        /// 方法的缓存属性(线性不安全)
        /// </summary>
        [AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
        public class CacheAttribute : AopAttribute
        {
            #region fields
            private short _index1 = -1;
            private short _index2 = -1;
            private short _index3 = -1;
            #endregion
    
            #region protected fields
            protected string Prefix = string.Empty;//缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀
            protected string Key = string.Empty;
            protected string BucketName = string.Empty;
            #endregion
    
            #region Otors
            /// <summary>
            /// 定义缓存关键字来缓存
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            protected CacheAttribute(string bucketName, string prefix)
            {
                BucketName = bucketName;
                Prefix = prefix;
            }
            /// <summary>
            /// 定义缓存关键字来缓存
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="key">缓存键</param>
            public CacheAttribute(string bucketName, string prefix, string key)
                : this(bucketName, prefix)
            {
                if (string.IsNullOrEmpty(key)) throw new ArgumentException("缓存键不能为空");
                Key = string.Format("{0}:{1}", Prefix, key);
            }
    
            /// <summary>
            /// 使用当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex">对应的当前参数的缓存键所在的参数索引位置</param>
            public CacheAttribute(string bucketName, string prefix, short keyIndex)
                : this(bucketName, prefix)
            {
                if (keyIndex < 0) throw new ArgumentException("关键值的参数索引需大于0");
                _index1 = keyIndex;
            }
    
            /// <summary>
            /// 使用多个当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex1">对应的当前参数的缓存键所在的参数索引位置1</param>
            /// <param name="keyIndex2">对应的当前参数的缓存键所在的参数索引位置2</param>
            public CacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2)
                : this(bucketName, prefix)
            {
                if (keyIndex1 < 0 || keyIndex2 < 0) throw new ArgumentException("关键值的参数索引需大于0");
                _index1 = keyIndex1;
                _index2 = keyIndex2;
            }
    
            /// <summary>
            /// 使用多个当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex1">对应的当前参数的缓存键所在的参数索引位置1</param>
            /// <param name="keyIndex2">对应的当前参数的缓存键所在的参数索引位置2</param>
            /// <param name="keyIndex3">对应的当前参数的缓存键所在的参数索引位置3</param>
            public CacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2, short keyIndex3)
                : this(bucketName, prefix)
            {
                if (keyIndex1 < 0 || keyIndex2 < 0 || keyIndex3 < 0) throw new ArgumentException("关键值的参数索引不能小于零");
                _index1 = keyIndex1;
                _index2 = keyIndex2;
                _index3 = keyIndex3;
            }
            #endregion
    
            #region override
    
            public override object PreCall(object[] inputArgs, out object[] outputs)
            {
                outputs = new object[0];
    
                var result = IocContainer.Resolve<ICacheService>(BucketName).Get<object>(GetKey(inputArgs));
                return result.Success ? result.Value : null;
            }
    
            public override void Called(object resultValue, object[] inputArgs, object[] outputs)
            {
                IocContainer.Resolve<ICacheService>(BucketName).Upsert<object>(GetKey(inputArgs), resultValue);
            }
    
            public override void OnException(Exception e, Dictionary<string, object> inputArgs)
            {
            }
    
            protected virtual string GetKey(object[] inputArgs)
            {
                if (string.IsNullOrEmpty(Key))
                {
                    if (Math.Max(Math.Max(_index1, _index2), _index3) >= inputArgs.Count()) throw new ArgumentException("关键值的参数索引不能大于参数总个数");
                    string prefix1 = _index1 >= 0 ? inputArgs[_index1].ToJson() : "";
                    string prefix2 = _index2 >= 0 ? "-" + inputArgs[_index2].ToJson() : "";
                    string prefix3 = _index3 >= 0 ? "-" + inputArgs[_index3].ToJson() : "";
                    Key = string.Format("{0}:{1}{2}{3}",Prefix, prefix1, prefix2, prefix3);
                }
                return Key;
            }
    
            #endregion
        }
    }

    输入参数是对象,通过输入参数对象的属性的值来作为缓存键

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MJD.Framework.Aop.Cache
    {
        /// <summary>
        /// 根据属性来设置缓存的关键字
        /// </summary>
        public class CacheWithPropertyAttribute : CacheAttribute
        {
            #region fields
            private List<string> _properties = null;
            private byte _index = 0;
            #endregion
    
            #region Octors
            /// <summary>
            /// 根据方法的第一个参数的属性设置
            /// </summary>
            /// <param name="bucketName">缓存Bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="properties">属性名</param>
            public CacheWithPropertyAttribute(string bucketName, string prefix, params string[] properties)
                : base(bucketName, prefix)
            {
                if (properties == null || properties.Length == 0) throw new ArgumentException("设置的properties个数必须大于1");
                _properties = properties.ToList();
            }
            /// <summary>
            /// 根据方法的第一个参数的属性设置
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="index">要设置为缓存的方法参数的索引,索引下标从0开始</param>
            /// <param name="properties">属性名</param>
            public CacheWithPropertyAttribute(string bucketName, string prefix, byte index, params string[] properties)
                : base(bucketName, prefix)
            {
                if (index < 0) throw new ArgumentException("关键值的参数索引不能小于零");
                if (properties == null || properties.Length == 0) throw new ArgumentException("设置的properties个数必须大于1");
                _properties = properties.ToList();
                _index = index;
            }
            #endregion
    
            #region override
            public override object PreCall(object[] inputArgs, out object[] outputs)
            {
                return base.PreCall(inputArgs, out outputs);
            }
            #endregion
    
            protected override string GetKey(object[] inputArgs)
            {
                if (string.IsNullOrEmpty(Key))
                {
                    Key += base.Prefix + ":";
                    object instance = inputArgs[_index];
                    foreach (var property in _properties)
                    {
                        Key += GetPropertyValue(instance, property) + "-";
                    }
                }
                return Key.TrimEnd('-');
            }
    
            private object GetPropertyValue(object instance, string propertyName)
            {
                BindingFlags flag = BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.IgnoreCase | BindingFlags.Public;
                Type type = instance.GetType();
                var property = type.GetProperty(propertyName, flag);
                if (property == null) throw new ArgumentException(string.Format("获取缓存出错,类型{0}中没有找到属性{1}", type, propertyName));
                return property.GetValue(instance, null);
            }
        }
    }

    通过输入参数索引位置移除缓存的aop属性

    using MJD.Framework.CrossCutting;
    using MJD.Framework.ICache;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace MJD.Framework.Aop.Cache
    {
        /// <summary>
        /// 移除缓存特性
        /// </summary>
        public class RemoveCacheAttribute : CacheAttribute
        {
            #region Otors
            /// <summary>
            /// 定义缓存关键字来缓存
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            protected RemoveCacheAttribute(string bucketName, string prefix)
                : base(bucketName, prefix)
            {
            }
            /// <summary>
            /// 定义缓存关键字来缓存
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="key">缓存键</param>
            public RemoveCacheAttribute(string bucketName, string prefix, string key)
                : base(bucketName, prefix, key)
            {
            }
    
            /// <summary>
            /// 使用当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex">对应的当前参数的缓存键所在的参数索引位置</param>
            public RemoveCacheAttribute(string bucketName, string prefix, short keyIndex)
                : base(bucketName, prefix, keyIndex)
            {
            }
    
            /// <summary>
            /// 使用多个当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex1">对应的当前参数的缓存键所在的参数索引位置1</param>
            /// <param name="keyIndex2">对应的当前参数的缓存键所在的参数索引位置2</param>
            public RemoveCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2)
                : base(bucketName, prefix, keyIndex1, keyIndex2)
            {
            }
    
            /// <summary>
            /// 使用多个当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex1">对应的当前参数的缓存键所在的参数索引位置1</param>
            /// <param name="keyIndex2">对应的当前参数的缓存键所在的参数索引位置2</param>
            /// <param name="keyIndex3">对应的当前参数的缓存键所在的参数索引位置3</param>
            public RemoveCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2, short keyIndex3)
                : base(bucketName, prefix, keyIndex1, keyIndex2, keyIndex3)
            {
            }
            #endregion
    
            #region override
            public override void Called(object resultValue, object[] inputArgs, object[] outputs)
            {
            }
    
            public override object PreCall(object[] inputArgs, out object[] outputs)
            {
                IocContainer.Resolve<ICacheService>(BucketName).Remove(GetKey(inputArgs));
                outputs = new object[0];
                return null;
            }
            #endregion
        }
    }

     通过输入参数属性的值作为缓存键来移除缓存

    using MJD.Framework.CrossCutting;
    using MJD.Framework.ICache;
    
    namespace MJD.Framework.Aop.Cache
    {
        /// <summary>
        /// 移除缓存特性(调用成功后移除)
        /// </summary>
        public class RemoveCacheWithPropertyAttribute : CacheWithPropertyAttribute
        {
            #region Octors
            /// <summary>
            /// 根据方法的第一个参数的属性设置
            /// </summary>
            /// <param name="bucketName">缓存Bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="properties">属性名</param>
            public RemoveCacheWithPropertyAttribute(string bucketName, string prefix, params string[] properties)
                : base(bucketName, prefix, properties)
            {
            }
            /// <summary>
            /// 根据方法的第一个参数的属性设置
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="index">要设置为缓存的方法参数的索引,索引下标从0开始</param>
            /// <param name="properties">属性名</param>
            public RemoveCacheWithPropertyAttribute(string bucketName, string prefix, byte index, params string[] properties)
                : base(bucketName, prefix, index, properties)
            {
            }
            #endregion
    
            #region override
            public override void Called(object resultValue, object[] inputArgs, object[] outputs)
            {
                IocContainer.Resolve<ICacheService>(BucketName).Remove(GetKey(inputArgs));
            }
    
            public override object PreCall(object[] inputArgs, out object[] outputs)
            {
                //IocContainer.Resolve<ICacheService>(BucketName).Remove(GetKey(inputArgs));
                outputs = new object[0];
                return null;
            }
            #endregion
        }
    }

    更新1

    using MJD.Framework.CrossCutting;
    using MJD.Framework.ICache;
    
    namespace MJD.Framework.Aop.Cache
    {
        /// <summary>
        /// 更新缓存特性
        /// </summary>
        public class UpdateCacheAttribute : CacheAttribute
        {
            #region Otors
            /// <summary>
            /// 定义缓存关键字来缓存
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            protected UpdateCacheAttribute(string bucketName, string prefix)
                : base(bucketName, prefix)
            {
            }
            /// <summary>
            /// 定义缓存关键字来缓存
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="key">缓存键</param>
            public UpdateCacheAttribute(string bucketName, string prefix, string key)
                : base(bucketName, prefix, key)
            {
            }
    
            /// <summary>
            /// 使用当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex">对应的当前参数的缓存键所在的参数索引位置</param>
            public UpdateCacheAttribute(string bucketName, string prefix, short keyIndex)
                : base(bucketName, prefix, keyIndex)
            {
            }
    
            /// <summary>
            /// 使用多个当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex1">对应的当前参数的缓存键所在的参数索引位置1</param>
            /// <param name="keyIndex2">对应的当前参数的缓存键所在的参数索引位置2</param>
            public UpdateCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2)
                : base(bucketName, prefix, keyIndex1, keyIndex2)
            {
            }
    
            /// <summary>
            /// 使用多个当前参数来缓存,索引位置从0开始
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="keyIndex1">对应的当前参数的缓存键所在的参数索引位置1</param>
            /// <param name="keyIndex2">对应的当前参数的缓存键所在的参数索引位置2</param>
            /// <param name="keyIndex3">对应的当前参数的缓存键所在的参数索引位置3</param>
            public UpdateCacheAttribute(string bucketName, string prefix, short keyIndex1, short keyIndex2, short keyIndex3)
                : base(bucketName, prefix, keyIndex1, keyIndex2, keyIndex3)
            {
            }
            #endregion
    
            #region override
            public override void Called(object resultValue, object[] inputArgs, object[] outputs)
            {
                IocContainer.Resolve<ICacheService>(BucketName).Upsert<object>(GetKey(inputArgs), resultValue);
            }
    
            public override object PreCall(object[] inputArgs, out object[] outputs)
            {
                outputs = new object[0];
                return null;
            }
            #endregion
        }
    }

    更新2

    using MJD.Framework.CrossCutting;
    using MJD.Framework.ICache;
    
    namespace MJD.Framework.Aop.Cache
    {
        /// <summary>
        /// 更新缓存特性
        /// </summary>
        public class UpdateCacheWithPropertyAttribute : CacheWithPropertyAttribute
        {
    
            #region Octors
            /// <summary>
            /// 根据方法的第一个参数的属性设置
            /// </summary>
            /// <param name="bucketName">缓存Bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="properties">属性名</param>
            public UpdateCacheWithPropertyAttribute(string bucketName, string prefix, params string[] properties)
                : base(bucketName, prefix, properties)
            {
            }
            /// <summary>
            /// 根据方法的第一个参数的属性设置
            /// </summary>
            /// <param name="bucketName">缓存bucket</param>
            /// <param name="prefix">缓存的前缀,避免使用ID作为缓存键时与其他缓存冲突,必须是独一无二的前缀</param>
            /// <param name="index">要设置为缓存的方法参数的索引,索引下标从0开始</param>
            /// <param name="properties">属性名</param>
            public UpdateCacheWithPropertyAttribute(string bucketName, string prefix, byte index, params string[] properties)
                : base(bucketName, prefix, index, properties)
            {
            }
            #endregion
            
            #region override
            public override void Called(object resultValue, object[] inputArgs, object[] outputs)
            {
                IocContainer.Resolve<ICacheService>(BucketName).Upsert<object>(GetKey(inputArgs), resultValue);
            }
    
            public override object PreCall(object[] inputArgs, out object[] outputs)
            {
                outputs = new object[0];
                return null;
            }
            #endregion
        }
    }
  • 相关阅读:
    盒子阴影——Box-shadow
    Flex布局
    常用正则表达式
    选择器
    上传头像功能
    利用百度地图API获取用户浏览器所在省市区
    Android Studio编译运行卡慢的解决方案
    Laravel5.5 解决时区设置差8个小时解决办法
    Git:远程代码与本地冲突常见解决方法
    vue-element-admin解决跨域问题
  • 原文地址:https://www.cnblogs.com/flyingaway/p/8523332.html
Copyright © 2011-2022 走看看