手写redis@Cacheable注解 参数java对象作为key值详解
1.实现方式说明
本文在---- 手写redis @ Cacheable注解支持过期时间设置 的基础之上进行扩展。
1.1问题说明
@ Cacheable(key = “'leader'+#p0 +#p1 +#p2” )一般用法,#p0表示方法的第一个参数,#p1表示第二个参数,以此类推。
目前方法的第一个参数为Java的对象,但是原注解只支持Java的的基本数据类型。
1.2实现步骤
1.在原注解中加入新的参数,
objectIndexArray表示哪几个角标参数(从0开始)为java对象,objectFieldArray表示对应位置该对象的字段值作为key
2.如何获取参数的对象以及该字段的值
使用的java的反射,拼接get方法获取该字段值。
2.源代码
修改java注解@ExtCacheable,本文中使用@NewCacheable
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 NewCacheable { String key() default ""; int[] objectIndexArray(); String[] objectFieldArray(); int expireTime() default 1800;//30分钟 }
SpringAop切面NewCacheableAspect
获取AOP整体流程没有任何变化
主要是关键值获取的方式,发生了变化
使用Java的反射技术
完整代码如下:
package com.huajie.aspect; import com.huajie.annotation.NewCacheable; import com.huajie.utils.RedisUtil; import com.huajie.utils.StringUtil; import lombok.extern.slf4j.Slf4j; 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 java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * redis缓存处理 不适用与内部方法调用(this.)或者private */ @Component @Aspect @Slf4j public class NewCacheableAspect { @Autowired private RedisUtil redisUtil; @Pointcut("@annotation(com.huajie.annotation.NewCacheable)") public void annotationPointcut() { } @Around("annotationPointcut()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { // 获得当前访问的class Class<?> className = joinPoint.getTarget().getClass(); // 获得访问的方法名 String methodName = joinPoint.getSignature().getName(); // 得到方法的参数的类型 Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes(); Object[] args = joinPoint.getArgs(); String key = ""; int expireTime = 3600; try { // 得到访问的方法对象 Method method = className.getMethod(methodName, argClass); method.setAccessible(true); // 判断是否存在@ExtCacheable注解 if (method.isAnnotationPresent(NewCacheable.class)) { NewCacheable annotation = method.getAnnotation(NewCacheable.class); key = getRedisKey(args, annotation); expireTime = getExpireTime(annotation); } } catch (Exception e) { throw new RuntimeException("redis缓存注解参数异常", e); } log.info(key); boolean hasKey = redisUtil.hasKey(key); if (hasKey) { return redisUtil.get(key); } else { Object res = joinPoint.proceed(); redisUtil.set(key, res); redisUtil.expire(key, expireTime); return res; } } private int getExpireTime(NewCacheable annotation) { return annotation.expireTime(); } private String getRedisKey(Object[] args, NewCacheable annotation) throws Exception{ String primalKey = annotation.key(); // 获取#p0...集合 List<String> keyList = getKeyParsList(primalKey); for (String keyName : keyList) { int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", "")); Object parValue = getParValue(annotation, keyIndex, args); primalKey = primalKey.replace(keyName, String.valueOf(parValue)); } return primalKey.replace("+", "").replace("'", ""); } private Object getParValue(NewCacheable annotation, int keyIndex, Object[] args) throws Exception{ int[] objectIndexArray = annotation.objectIndexArray(); String[] objectFieldArray = annotation.objectFieldArray(); if (existsObject(keyIndex, objectIndexArray)) { return getParValueByObject(args, keyIndex, objectFieldArray); } else { return args[keyIndex]; } } private Object getParValueByObject(Object[] args, int keyIndex, String[] objectFieldArray) throws Exception { Class cls = args[keyIndex].getClass(); Method method; if(objectFieldArray!=null&&objectFieldArray.length>=keyIndex){ method = cls.getMethod("get" + StringUtil.firstCharToUpperCase(objectFieldArray[keyIndex])); }else{ method = cls.getMethod("get" + StringUtil.firstCharToUpperCase(cls.getFields()[0].getName())); } method.setAccessible(true); log.info(method.getName()); return method.invoke(args[keyIndex]); } private boolean existsObject(int keyIndex, int[] objectIndexArray) { if (objectIndexArray == null || objectIndexArray.length <= 0) { return false; } for (int i = 0; i < objectIndexArray.length; i++) { if (keyIndex == objectIndexArray[i]) { return true; } } return false; } // 获取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; } }
3.测试
业务模块使用方法controller
@RequestMapping("queryQuotaTreeData") @ResponseBody public List<TreeNode> getTreeData() { QuotaManage quotaManage = new QuotaManage(); quotaManage.setQuotaName("测试22222"); List<TreeNode> list = this.quotaManageService.queryQuotaTreeData(quotaManage); return list; }
实现层objectIndexArray中的{0}表示第0个参数,objectFieldArray中的“quotaName”表示对应对象中的字段名称
@Override @NewCacheable(key="test+#p0",objectIndexArray = {0},objectFieldArray = {"quotaName"}) public List<TreeNode> queryQuotaTreeData(QuotaManage quotaManage) { List<TreeNode> returnNodesList = new ArrayList<TreeNode>(); List<TreeNode> nodeList = this.mapper.queryQuotaTreeData(); returnNodesList = treeUtils.getParentList(nodeList); log.info(nodeList.size()+""); return returnNodesList; }
控制台截图拼接的get方法名称和获取的字段值
Redis的截图
以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。
原文出处:https://blog.csdn.net/xiewenfeng520/article/details/84864120
相关文章
- 这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
- 这篇文章主要介绍了R语言删除指定变量或对象的操作方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06
- 这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
如何在Spring WebFlux的任何地方获取Request对象
这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26- 这篇文章主要介绍了JavaScript预解析,对象的的相关资料,小编觉得这篇文章写的还不错,需要的朋友可以参考下,希望能够给你带来帮助...2021-11-10
牛叉的Jquery――Jquery与DOM对象的互相转换及DOM的三种操作
只有jQuery对象才能调用jQuery类库的各种函数,同样有些dom对象的属性和方法在jQuery上也是无法调用的,不过基本上jQuery类库提供的函数包含了所有的dom操作。这就需要我们知道如何将jQuery对象和DOM的相互转换的方法。1...2015-10-30- 这篇文章主要介绍了解决Springboot get请求是参数过长的情况,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
PHP中empty和isset对于参数结构的判断及empty()和isset()的区别
废话不多说了,直接给大家贴代码了。<?php class test{} $a1 = null; $a2 = ""; //$a3 = $a4 = 0; $a5 = '0'; $a6 = false; $a7 = array(); //var $a8; $a9 = new test(); for ($i=1; $i <=9 ; $i++) {...2015-11-24- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
- mysql安装成功后有几个默认的配置模板,列表如下: my-huge.cnf : 用于高端产品服务器,包括1到2GB RAM,主要运行mysql my-innodb-heavy-4G.ini : 用于只有innodb的安装,最多有4GB RAM,支持大的查询和低流量 my-large.cnf : 用于...2015-03-15
- 这篇文章主要给大家介绍了关于C#中out参数、ref参数与值参数的用法及区别的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 这篇文章主要介绍了C#泛型的类型参数约束的相关资料,文中讲解非常细致,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下...2020-07-31
- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- js调试中经常会碰到输出的内容是对象而无法打印的时候,光靠alert只能打印出object标示,却不能打印出来里面的内容,甚是不方便,于是各方面整理总结了如下一个函数,能够将数组或者对象这类的结果一一打印出来,具体代码如下: fu...2015-10-21
- 这篇文章主要介绍了vue+axios全局添加请求头和参数操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-24
- 这篇文章主要介绍了SpringBoot接口接收json参数解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-19
处理@PathVariable注解允许参数为空、允许不传参数的问题
这篇文章主要介绍了处理@PathVariable注解允许参数为空、允许不传参数的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-23- 这篇文章主要介绍了pytorch 实现冻结部分参数训练另一部分,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-27
- 这篇文章主要介绍了详解Java后端优雅验证参数合法性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
- 这篇文章主要介绍了C#向线程中传递多个参数的解决方法(两种)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下...2020-06-25