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 = -;
private short _index2 = -;
private short _index3 = -;
#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 < ) 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 < || keyIndex2 < ) 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 < || keyIndex2 < || keyIndex3 < ) throw new ArgumentException("关键值的参数索引不能小于零");
_index1 = keyIndex1;
_index2 = keyIndex2;
_index3 = keyIndex3;
}
#endregion #region override public override object PreCall(object[] inputArgs, out object[] outputs)
{
outputs = new object[]; 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 >= ? inputArgs[_index1].ToJson() : "";
string prefix2 = _index2 >= ? "-" + inputArgs[_index2].ToJson() : "";
string prefix3 = _index3 >= ? "-" + 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 = ;
#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 == ) 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 < ) throw new ArgumentException("关键值的参数索引不能小于零");
if (properties == null || properties.Length == ) 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[];
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[];
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[];
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[];
return null;
}
#endregion
}
}
AOP缓存实现的更多相关文章
- SpringBoot集成Redis实现缓存处理(Spring AOP实现)
第一章 需求分析 计划在Team的开源项目里加入Redis实现缓存处理,因为业务功能已经实现了一部分,通过写Redis工具类,然后引用,改动量较大,而且不可以实现解耦合,所以想到了Spring框架的A ...
- SpringBoot AOP控制Redis自动缓存和更新
导入redis的jar包 <!-- redis --> <dependency> <groupId>org.springframework.boot</gro ...
- 在 WPF 客户端实现 AOP 和接口缓存
随着业务越来越复杂,最近决定把一些频繁查询但是数据不会怎么变更的接口做一下缓存,这种功能一般用 AOP 就能实现了,找了一下客户端又没现成的直接可以用,嗐,就只能自己开发了. 代理模式和AOP 理解代 ...
- C#.NET利用ContextBoundObject和Attribute实现AOP技术--AOP事务实现例子
我前两天看见同事用写了用AOP技术实现缓存的方案,于是好奇看了一下这是怎么实现的.原来是用了.NET中的一个类ContextBoundObject和Attribute相关技术.其实个类在.NET Fr ...
- 从壹开始前后端分离 40 || 完美基于AOP的接口性能分析
旁白音:本文是不定时更新的.net core,当前主线任务的Nuxt+VueAdmin教程的 nuxt.js 之 tibug项目已上线,大家可以玩一玩:http://123.206.33.109:70 ...
- Lind.DDD敏捷领域驱动框架~Lind.DDD各层介绍
回到目录 Lind.DDD项目主要面向敏捷,快速开发,领域驱动等,对于它的分层也是能合并的合并,比之前大叔的框架分层更粗糙一些,或者说更大胆一些,在开发人员使用上,可能会感觉更方便了,更益使用了,这就 ...
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题总结
下载地址: http://pan.baidu.com/s/1qWDinyk 一 开发环境 1.动态web工程 2.部分依赖 hibernate-release-4.1.0.Final.zip hibe ...
- 从壹开始前后端分离[.NetCore] 37 ║JWT完美实现权限与接口的动态分配
缘起 本文已经有了对应的管理后台,地址:https://github.com/anjoy8/Blog.Admin 哈喽大家好呀!又过去一周啦,这些天小伙伴们有没有学习呀,已经有一周没有更新文章了,不过 ...
- 壹佰文章最全总结| 《关于ASP.NETCore的分享之路》
学习路线图 (关于学习ASP.NET Core需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...
随机推荐
- RawConfigParser 与 ConfigParser ——Python的配件文件读取模块
一般情况都是使用ConfigParser这个方法,但是当我们配置中有%(filename)s这种格式的配置的时候,可能会出现以下问题: configparser.InterpolationMissin ...
- es6中的对象的可计算的属性名
先简单的啰嗦一下对象的属性: var obj = { a:2 } 要访问obj中a的位置,方法:1. obj.a //2 2..obj ["a"] ...
- Python学习的路上,Anaconda送你一双遮天神翼
一.背景 最近在学习python,发现在本地搭建python环境的时候,要是想要同时搭建不同python版本的环境,就比较麻烦,很容易就出现冲突了,很是头疼.然后光明就出现这山重水复疑无路的时候, ...
- VM虚拟机扩展硬盘容量
VM虚拟机扩展硬盘容量 第一步,关闭系统,给虚拟机硬盘增加空间. 第二步,启动系统.查看硬盘大小和分区情况. 第三步,分区. 第四步,格式化分区. 第五步,挂载. 第六步,开机自动挂载. 第一步: 当 ...
- 面试:C++实现访问者模式
参考:深入应用C++11,访问者模式 #include <iostream> class ConcreteElement1; class ConcreteElement2; class V ...
- iOS ipa包瘦身,iOS8及以下text段超60MB
前沿 很早之前写过一篇相关文章,不过博客主机上跑路了之后数据没了,凭着记忆补了下相关资料 ipa安装包瘦身 清理无用图片,图片压缩(PNG换WebP和JPG),处于某种不可抗拒的原因,导致有部分3X图 ...
- Maven教程(2)--Maven的配置,MyEclipse与Eclipse的配置
1.修改Maven的 repository的路径 2.找到mirrors 使用阿里云镜像 <mirror> <id>alimaven</id> <name&g ...
- ElasticSearch入门简介
ElasticSearch是基于Apache Lucene的分布式搜索引擎, 提供面向文档的搜索服务.本文以6.2.3版本为例介绍ElasticSearch的应用. 本文首先介绍ElasticSear ...
- 修改任务显示WrkTaskIp.aspx页面
环境:Sharepoint2010 需求:在审批任务页面中插入或显示表单或列表内容,让内容与审核在同一页面上. 修改文件:WrkTaskIp.aspx(改前记得备份) 文件所在的路径:C:\Progr ...
- html 颜色选择器 亲测,很好用
@*以下 是测试html 颜色选择器的*@ @*<a href="#" mce_href="#" onclick="initColorPicke ...