SpringAOP中通过JoinPoint获取值,并且实现redis注解
在Java8之前,代码编译为class文件后,方法参数的类型固定,但是方法名称会丢失,方法名称会变成arg0、arg1….。在Java8开始可以在class文件中保留参数名
public void tet(JoinPoint joinPoint) {// 下面两个数组中,参数值和参数名的个数和位置是一一对应的。Object[] args = joinPoint.getArgs(); // 参数值String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames(); // 参数名// 得到被代理的方法Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();// 得到被代理的方法上的注解Class modelType = method.getAnnotation(RedisCache.class).type();// 得到被代理方法的返回值类型Class returnType = ((MethodSignature) joinPoint.getSignature()).getReturnType()
}
@Cacheable注解作用,将带有该注解方法的返回值存放到redis的的中;
使用方法在方法上使用@Cacheable(键=“测试+#P0 + P1#…”)
表示键值为测试+方法第一个参数+方法第二个参数,值为该方法的返回值。
以下源代码表示获取人员列表,Redis的中存放的关键值为’领袖’+ leaderGroupId + UUID + yearDetailId
@Override@Cacheable(key="'leader'+#p0+#p1+#p2",value="leader")public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {return sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);}
等同于
@Overridepublic List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {String key = "leader" + leaderGroupId + uuid + yearDetailId;// 判断缓存是否存在redis中boolean hasKey = redisUtil.hasKey(key);if (hasKey) {//如果存在 返还redis中的值Object leadersList = redisUtil.get(key);return (List<Leader>) leadersList;} else {List<Leader> leadersQuotaDetailList = sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);//将查询结果存放在redis中redisUtil.set(key, leadersQuotaDetailList);return leadersQuotaDetailList;}}
缓存配置类RedisConfig
package com.huajie.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;/*** Redis缓存配置类*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;@Value("${spring.redis.timeout}")private int timeout;// 自定义缓存key生成策略@Beanpublic KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, java.lang.reflect.Method method, Object... params) {StringBuffer sb = new StringBuffer();sb.append(target.getClass().getName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();}};}// 缓存管理器@Beanpublic CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);// 设置缓存过期时间cacheManager.setDefaultExpiration(10000);return cacheManager;}@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();template.setConnectionFactory(factory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}private void setSerializer(StringRedisTemplate template) {@SuppressWarnings({ "rawtypes", "unchecked" })Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);template.setValueSerializer(jackson2JsonRedisSerializer);}
}
Redis的依赖引入,配置文件,工具类RedisUtil,网上几个版本都类似,本文参考以下版本传送门
https://www.jb51.net/article/233562.htm
准备工作做好之后开始正式编写注解@Cacheable nextkey()用做二级缓存本文中不会用到
nextKey用法详情> 设计模式(实战) - 责任链模式 <
创建的Java的注解@ExtCacheable
package com.huajie.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtCacheable { String key() default ""; String nextKey() default ""; int expireTime() default 1800;//30分钟
}
SpringAop切面CacheableAspect
package com.huajie.aspect;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.huajie.annotation.ExtCacheable;
import com.huajie.utils.RedisUtil;/*** redis缓存处理* 不适用与内部方法调用(this.)或者private*/
@Component
@Aspect
public class CacheableAspect { @Autowiredprivate RedisUtil redisUtil;@Pointcut("@annotation(com.huajie.annotation.ExtCacheable)")public void annotationPointcut() {}@Around("annotationPointcut()")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {// 获得当前访问的classClass<?> className = joinPoint.getTarget().getClass();// 获得访问的方法名String methodName = joinPoint.getSignature().getName();// 得到方法的参数的类型Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();Object[] args = joinPoint.getArgs();String key = "";int expireTime = 1800;try {// 得到访问的方法对象Method method = className.getMethod(methodName, argClass);method.setAccessible(true);// 判断是否存在@ExtCacheable注解if (method.isAnnotationPresent(ExtCacheable.class)) {ExtCacheable annotation = method.getAnnotation(ExtCacheable.class);key = getRedisKey(args,annotation);expireTime = getExpireTime(annotation);}} catch (Exception e) {throw new RuntimeException("redis缓存注解参数异常", e);}// 获取缓存是否存在boolean hasKey = redisUtil.hasKey(key);if (hasKey) {return redisUtil.get(key);} else {//执行原方法(java反射执行method获取结果)Object res = joinPoint.proceed();//设置缓存redisUtil.set(key, res);//设置过期时间redisUtil.expire(key, expireTime);return res;}}private int getExpireTime(ExtCacheable annotation) {return annotation.expireTime();}private String getRedisKey(Object[] args,ExtCacheable annotation) {String primalKey = annotation.key();//获取#p0...集合List<String> keyList = getKeyParsList(primalKey);for (String keyName : keyList) {int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", ""));Object parValue = args[keyIndex];primalKey = primalKey.replace(keyName, String.valueOf(parValue));}return primalKey.replace("+","").replace("'","");}// 获取key中#p0中的参数名称private static List<String> getKeyParsList(String key) {List<String> ListPar = new ArrayList<String>();if (key.indexOf("#") >= 0) {int plusIndex = key.substring(key.indexOf("#")).indexOf("+");int indexNext = 0;String parName = "";int indexPre = key.indexOf("#");if(plusIndex>0){indexNext = key.indexOf("#") + key.substring(key.indexOf("#")).indexOf("+");parName = key.substring(indexPre, indexNext);}else{parName = key.substring(indexPre);}ListPar.add(parName.trim());key = key.substring(indexNext + 1);if (key.indexOf("#") >= 0) {ListPar.addAll(getKeyParsList(key));}}return ListPar;}
}
业务模块使用方法
@Override@ExtCacheable(key = "Leaders+#p0+#p1+#p2")// 手机端获取领导人员列表public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {List<Leader> leadersQuotaDetailList = sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);return leadersQuotaDetailList;}
业务模块过期时间使用方法,5分钟过期
@Override@ExtCacheable(key = "mobileCacheFlag", expireTime = 60 * 5)public int cacheFlag() {int mobileCacheFlag = 1;mobileCacheFlag = sysIndexMapper.cacheFlag();return mobileCacheFlag;}
SpringAOP中通过JoinPoint获取值,并且实现redis注解相关推荐
- python 按键获取_Python中按键来获取指定的值
Python中按键来获取值,相对来说要容易些,毕竟只需要dict[key]就可以找到,但里面同样有个问题,如果其中的键不存在的话,会抛出异常,如果不用try...except...等异常处理机制的话, ...
- SpringAop中JoinPoint对象的使用方法
JoinPoint的用法 JoinPoint 对象 JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoi ...
- html 表单内容怎么获取不到,jquery中formdate一直获取不到对象中的[0]的值 包括本身也是一个空的数据怎么办?...
jquery中formdate一直获取不到对象中的[0]的值 包括本身也是一个空的数据怎么办? 再做一个前台的ajax方法 查网上用formdate方法上传.可是进了接口之后一直在控制台获取不到for ...
- pandas使用groupby.first函数、groupby.nth(0)函数获取每个组中的第一个值实战:groupby.first函数和groupby.nth函数对比(对待NaN的差异)
pandas使用groupby.first函数.groupby.nth(0)函数获取每个组中的第一个值实战:groupby.first函数和groupby.nth函数对比(对待NaN的差异) 目录
- pandas使用groupby.last函数获取每个组中的最后一个值实战:groupby.last函数获取每个组中的最后一个值、groupby.nth函数获取每个组中的最后一个值
pandas使用groupby.last函数获取每个组中的最后一个值实战:groupby.last函数获取每个组中的最后一个值.groupby.nth函数获取每个组中的最后一个值 目录
- java获取json中的某个值_接口测试之json中的key获取
在很多情况下我们在进行接口测试的时候都会有获取上个接口返回的json数据中的某个key值,然后下个接口调用这个key值.今天给大家讲解一下针对不同类型的json获取某个key的值. 一.首先是单纯ob ...
- Python语言学习:在python中,如何获取变量的本身字符串名字而非其值/内容及其应用(在代码中如何查找同值的所有变量名)
Python语言学习:在python中,如何获取变量的本身字符串名字而非其值/内容及其应用(在代码中如何查找同值的所有变量名) 目录
- datagrid如何获取一行数据中的某个字段值_redis 所支持的数据类型以及其应用场景...
1.支持的数据类型 redis 支持 String.hash.list.set.Sort set这几种数据类型,可用于缓存.事件发布订阅.高速队列等场景. String是最常用的数据类型,它能够存储任 ...
- list中抽出某一个字段的值_使用LINQ获取List列表中的某个字段值
使用LINQ获取列表中的某个字段值,下面以获取员工列表中的编号字段为例子. 1.使用Select方法 1 List emplayeeList = GetEmplayeeList(); //获取员工信息 ...
最新文章
- UWA平台新增【UI模块】和【粒子系统】检测功能!
- c语言变量名必须用小写 常量用大写,day02 -C语言 常量 变量 数据类型 进制转换 数据溢出...
- ABAP取字符串中的连续数字
- 导入jar时出现invalid LOC header (bad signature)
- GDCM:gdcm::Trace的测试程序
- linux有关网络服务的接口,linux系统有关网络服务接口定义是哪个?
- [Luogu2279][HNOI2003] 消防局的设立
- STM32的EXTI相关学习笔记
- 计算机中那些事儿(九):资料管理一些建议---理论篇
- 在Eclipse中实现C++ 11的完整支持
- SpringCloud实战(四)Sentinel自定义降级异常实战
- 【Django 2021年最新版教程12】GET POST请求参数 如何接收、判空、默认值
- 利用MQL5创建您自己的图形面板
- 微铺子点单系统具体介绍 - 争做国内最专业的微信商店平台,微信外卖订餐系统!...
- 第九节 html特殊文字符号
- 纯JS实现倒序九九乘法表 for循环
- --hot 和 --inline的区别
- 加班报税,体力不支?RPA智能申报,让报税轻松无忧
- Sharding Sphere ~ Sharding-jdbc分库分表、读写分离
- Android中按钮的点击事件的四种写法
热门文章
- redhat linux 5.6安装图解
- Xib/Storyboard碰到不同版本的Xcode真是想死啊!
- php里Array2xml
- 自定义验证控件CustomValidator
- 计算机基础7试题,大学计算机应用基础试题
- 4 谐波_技术文章—功率分析仪在IEC谐波的测试应用
- win7触摸板怎么关闭_笔记本电脑触摸板如何开关 笔记本电脑触摸板设置方法【详解】...
- matlab画置信区间图,matlab绘制带置信区间的双y轴图形 | 学步园
- 怎么把两个盒子显示在同一行_1个机顶盒2台电视机,怎么同时看电视?竟用一个分配器就行...
- pythonqt库_Python QT组件库qtwidgets的使用