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需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...
随机推荐
- python之斐波那契数列递归推导在性能方面的反思
在各种语言中,谈到递归首当其冲的是斐波那契数列,太典型了,简直就是标杆 一开始本人在学习递归也是如此,因为太符合逻辑了 后台在工作和学习中,不断反思递归真的就好嘛? 首先递归需要从后往前推导,所有数据 ...
- Linux学习笔记之二————Linux系统的文件和目录
一.Windows和Linux文件系统区别 1.在 windows 平台下,打开“计算机”,我们看到的是一个个的驱动器盘符: 每个驱动器都有自己的根目录结构,这样形成了多个树并列的情形,如图所示: ...
- PID file /run/zabbix/zabbix_server.pid not readable (yet?) after start. 报错解决
报错如下: [root@localhost zabbix]# systemctl start zabbix-server Job for zabbix-server.service failed be ...
- postgres 更新数据表
新增非空列: alter table t_test add column user_id integer; update t_test set user_id=0; alter table t_tes ...
- Kafka实战-入门
1.概述 经过一个多月的时间观察,业务上在集成Kafka后,各方面还算稳定,这里打算抽时间给大家分享一下Kafka在实际场景中的一些使用心得.本篇博客打算先给大家入个门,让大家对Kafka有个初步的了 ...
- Spring Boot初识(3)- Spring Boot整合Swagger
一.本文介绍 如果Web项目是完全前后端分离的话(我认为现在完全前后端分离已经是趋势了)一般前端和后端交互都是通过接口的,对接口入参和出参描述的文档就是Mock文档.随着接口数量的增多和参数的个数增加 ...
- golang map输出排序
由于GoLang Map 内部存储是无序的,当需要按顺序获得map存储的key -value值时,应该对遍历出来的结果进行重新排序: 在go 1.8版本后,提供的slice sort 功能使排序更简单 ...
- Java基础之Java 修饰符
前言:Java内功心法之Java 修饰符,看完这篇你向Java大神的路上又迈出了一步(有什么问题或者需要资料可以联系我的扣扣:734999078) Java语言提供了很多修饰符,主要分为以下两类: 访 ...
- 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)
第8章 压缩和存储(Hive高级)8.1 Hadoop源码编译支持Snappy压缩8.1.1 资源准备8.1.2 jar包安装8.1.3 编译源码8.2 Hadoop压缩配置8.2.1 MR支持的压缩 ...
- Spring JDBCTemplate连接SQL Server之初体验
前言 在没有任何框架的帮助下我们操作数据库都是用jdbc,耗时耗力,那么有了Spring,我们则不用重复造轮子了,先来试试Spring JDBC增删改查,其中关键就是构造JdbcTemplate类. ...