手写redis@Cacheable注解 参数java对象作为key值详解

网友投稿 369 2022-09-05


手写redis@Cacheable注解 参数java对象作为key值详解

目录1.实现方式说明1.1问题说明1.2实现步骤2.源代码3.测试

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.lvqzvOmDNvXang.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 {

http:// 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 keyList = getKeyParsList(primalKey);http://

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 getKeyParsList(String key) {

List ListPar = new ArrayList();

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 getTreeData() {

QuotaManage quotaManage = new QuotaManage();

quotaManage.setQuotaName("测试22222");

List list = this.quotaManageService.queryQuotaTreeData(quotaManage);

return list;

}

实现层objectIndexArray中的{0}表示第0个参数,objectFieldArray中的“quotaName”表示对应对象中的字段名称

@Override

@NewCacheable(key="test+#p0",objectIndexArray = {0},objectFieldArray = {"quotaName"})

public List queryQuotaTreeData(QuotaManage quotaManage) {

List returnNodesList = new ArrayList();

List nodeList = this.mapper.queryQuotaTreeData();

returnNodesList = treeUtils.getParentList(nodeList);

log.info(nodeList.size()+"");

return returnNodesList;

}

控制台截图拼接的get方法名称和获取的字段值

Redis的截图


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:安装python包(pycharm安装python包)
下一篇:python实现数据仓库ETL(python 数据仓库)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~