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需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...
随机推荐
- linux中一些简便的命令之tac/comm
tac tac是cat的反写,即反序显示文件内容 如文件a.txt内容如下: 1 2 3 4 5 则tac a.txt打印如下: 54321 我们可以使用awk来实现tac的功能: awk '{arr ...
- Ubuntu16.04安装Anaconda (转)
一. Anaconda下载 Anaconda 官方下载链接: https://www.continuum.io/downloads 根据自己的系统选择下载32位还是64位. 二. 进入下载目录 如 ...
- oracle查看当前用户,数据库实例
#sysdba用户登录[oracle@oracle ~]$ sqlplus / as sysdba #查看当前用户sql>show user; #查看当前数据库实例sql>show par ...
- Android模拟微信主页面的Demo
Android模拟微信主页面的Demo 效果图如下: 项目结构图如下: ContanctFragment: package com.demo.moniwexin; import android.app ...
- Android应用系列:手把手教你做一个小米通讯录(附图附源码)
前言 最近心血来潮,突然想搞点仿制品玩玩,很不幸小米成为我苦逼的第一个试验品.既然雷布斯的MIUI挺受欢迎的(本人就是其的屌丝用户),所以就拿其中的一些小功能做一些小demo来玩玩.小米的通讯录大家估 ...
- CynosDB技术详解——存储集群管理
本文由腾讯云数据库发表 前言 CynosDB是架构在CynosFS之上的分布式关系数据库系统,为最大化利用存储资源,平衡资源之间的竞争,检查资源使用情况,需要一套高效稳定的分布式集群管理系统(SCM: ...
- k8s小工具
1.Kubectx kubectx是一个在多集群和多命名空间的时候使用的非常好用的工具,kubectx与kubens绑定,kubectx用来在集群之间切换,kubens用来切换namespace. # ...
- JVM参数以及用法
工作以后,发觉真的几乎没有像大学那样空闲的时间,坐下来看看书写写博客了.最近的一篇博客距离现在已经近一个多月了,最近也在复习Java的东西,准备校招,看了看JVM的东西,就当作记笔记. (一)JVM参 ...
- 域名系统DNS简介
域名系统(Domain Name System, DNS)是互联网的核心应用层协议之一, 它用于查询域名对应的IP地址.在使用域名访问任何网络资源时都需要先进行域名解析. www.cnblogs.co ...
- vmware--查看链接克隆依赖关系
我们都知道,虚拟机克隆有完全克隆和链接克隆两种克隆方式.当根据模版去链接克隆出很多机器时,时间一长或者把克隆后的机器改名了,我们就忘记了哪台机器是克隆出来的,哪台是直接装的.如果不小心把模版机器给删除 ...