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需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...
随机推荐
- Django model update的各种用法介绍
Django开发过程中对表(model)的增删改查是最常用的功能之一,本文介绍笔者在使用model update过程中遇到的那些事 model update常规用法 假如我们的表结构是这样的 clas ...
- [源码]Delphi源码免杀之函数动态调用 实现免杀的下载者
[免杀]Delphi源码免杀之函数动态调用 实现免杀的下载者 2013-12-30 23:44:21 来源:K8拉登哥哥's Blog 自己编译这份代码看看 过N多杀软 没什么技 ...
- List通过HashSet去重
//JAVA中//使用hashset去重复,set为重复的集合,可以通过new ArrayList(set)转换成list HashSet<HashMap<String, String&g ...
- JAVA发送http get/post请求,调用http接口、方法
import java.io.BufferedReader; import java.io.IOException;import java.io.InputStream; import java.io ...
- .NET Core 2.0 Preview 1发布下载和文档
.NET Core 2.0.0 Preview 1 发布于 2017 5.10. 你可以通过 Visual Studio 2017 Preview 15.3, Visual Studio for Ma ...
- html css 其他常用 onclick跳转
opacity: 0.5. 0-1 透明度 cursor: pointer;手指 clear:both 清楚浮动 我是医生不是人 文本内容超出框word-wrap:break-word; word-b ...
- Spring Cloud Hystrix——熔断器
1.雪崩效应在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应.服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者 ...
- Http怎么处理长连接
http协议中有和keep alive特性,这个在http1.1中有, 可以保持浏览器和服务器之间保持着长连接,http本身是无连接的协议, 通过tcp实现数据的传输,处理长连接要注意什么时候数据服务 ...
- Rails项目防止时序攻击
时序攻击属于侧信道攻击/旁路攻击(Side Channel Attack),侧信道攻击是指利用信道外的信息,比如加解密的速度/加解密时芯片引脚的电压/密文传输的流量和途径等进行攻击的方式,一个词形容就 ...
- Spark新手入门——2.Hadoop集群(伪分布模式)安装
主要包括以下三部分,本文为第二部分: 一. Scala环境准备 查看 二. Hadoop集群(伪分布模式)安装 三. Spark集群(standalone模式)安装 查看 Hadoop集群(伪分布模式 ...