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的截图

以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。