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需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...
随机推荐
- 使用pyenv来管理python版本
使用pyenv可以很方便的切换python版本,而不会影响系统的python版本,对需要使用supervisor(仅支持python2)托管程序,项目使用python3开发的情况十分有用 pyenv的 ...
- spring cloud(断路器——初学四)
在分布式架构中,当某个服务单元发生故障后,能通过断路器的故障监控,向调用方返回一个错误响应,而不是长时间的等待. Netflix Hystrix 在Spring Cloud中使用了Hystrix 来实 ...
- go 通过http发送图片file内容
package main import ( "encoding/json" "fmt" "io/ioutil" "net/http ...
- Android开源系列:仿网易Tab分类排序控件实现
前言 产品:网易新闻那个Tab排序好帅. 开发:哦~ 然后这个东东在几天后就出现了..... (PS:差不多一年没回来写博客了~~~~(>_<)~~~~,顺便把名字从 enjoy风铃 修改 ...
- MapReduce-深度剖析
1.概述 在接触了第一代MapReduce和第二代MapReduce之后,或许会有这样的疑惑,我们从一些书籍和博客当中获取MapReduce的一些原理和算法,在第一代当中会有JobTrack,Task ...
- CSS 基础:HTML 标记与文档结构(1)<思维导图>
这段时间利用一下间隙时间学习了CSS的基础知识,主要目的是加深对CSS的理解,虽然个人主要工作基本都是后台开发,但是个人觉得系统学习一下CSS的基础还是很有必要的.下面我学习CSS时做的思维导图(全屏 ...
- tf.estimator.Estimator类的用法
官网链接:https://www.tensorflow.org/api_docs/python/tf/estimator/Estimator Estimator - 一种可极大地简化机器学习编程的高阶 ...
- JavaWeb学习 (九)————HttpServletRequest对象(一)
一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象 ...
- 正则表达式,re模块
一,正则表达式 正则表达式是对字符串操作的一种逻辑公式,我们一般使用正则表达式对字符串进行匹配和过滤,使用正则的优缺点,我们可以去http://tool.chinaz.com/regex/进行测试. ...
- 如何在 ASP.NET Core 测试中操纵时间?
有时候,我们会遇到一些跟系统当前时间相关的需求,例如: 只有开学季才允许录入学生信息 只有到了晚上或者周六才允许备份博客 注册满 3 天的用户才允许进行一些操作 某用户在 24 小时内被禁止发言 很显 ...