使用AOP实现+自定义注解 实现 缓存

一般做一个缓存处理,我们正常的做法是在需要缓存的方法中。

查询缓存是否存在,不存在,查询(DB或远程接口),如果数据存在,那么则缓存,否则下次记录查询。

当我们做1、2、3个方法这样写还行,如果有10、20个方法需要缓存,这样是不是就很繁琐了。。

所以,我们需要一个标签来做缓存,当然springcache提供有缓存的标签。还有各种策略。

但是,我就是要自己写一个。。

这个处理的方式原理就是通过AOP拦截自己定义的标签,然后通过标签中的参数,决定缓存多久,加标签的就做缓存。

单独几个的写法如下:

    @Autowired
    private RedisTemplate redisTemplate;
    /**查询数据*/
    public Object selectValue(String dicCode, String key) {
        String redisKey = "selectValue"+dicCode+key;
        Object result = redisTemplate.opsForValue().get(redisKey);
        if (null == result) {
            result = dictionaryDao.getDicInfoValue(dicCode, key);
            if (null != result) {
                redisTemplate.opsForValue().set(redisKey, result, 30, TimeUnit.SECONDS);
            }
        }
        return result;
    }

 

当我们做了几个后,修改成AOP+自定义注解

自定义注解:RedisCacheAT.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @desc:缓存注解-redis
 * @author 陈惟鲜
 * @date 2023年5月10日 下午7:36:28
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCacheAT {
    
    /**缓存时间,默认60秒*/
    public int times() default 60;
}

 

AOP切面:

RedisCacheAOP.java

import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

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.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;/**
 * @Desc : 本地缓存方法,方法上加上@LocalCache即可
 * @Company : 晨创科技
 * @author : Chenweixian 陈惟鲜
 * @Date : 2021年5月7日 下午7:47:56
 */
@SuppressWarnings({"rawtypes","unchecked"})
@Aspect
@Component
@Order(8) // @Order(1)数字越小优先级越高
public class RedisCacheAspect {
    
    @Resource
    private RedisTemplate redisTemplate;
    
    /**拦截所有controller包下的方法*/
    @Pointcut("@annotation(com.ccjr.core.logcollection.annotation.RedisCacheAT)")
    private void myMethod(){
    }
    
    /** 
     *  日志打印
     * @author : 陈惟鲜 chenweixian
     * @Date : 2022年8月8日 下午5:29:47
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("myMethod() && @annotation(cache)")  
    public Object doAround(ProceedingJoinPoint point, RedisCacheAT cache) throws Throwable {
        String class_name = point.getTarget().getClass().getName();
        String method_name = point.getSignature().getName();
        String requestStr = MyAopUtils.getRequestParam(point);
        String cacheKey = class_name + "." + method_name + requestStr;
     // 防止key过长,直接取md5值 cacheKey
= "redisCache:"+MD5Utils.getMD5(cacheKey); Object result = redisTemplate.opsForValue().get(cacheKey); if (null == result) { result = point.proceed();// result的值就是被拦截方法的返回值 if (null != result) { redisTemplate.opsForValue().set(cacheKey, result, cache.times(), TimeUnit.SECONDS); } } return result; } }

 

其中工具类获取请求参数

import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 *  切面拦截工具
 * @Company : 晨创科技
 * @author : Chenweixian
 * @Date : 2022年11月15日 下午10:45:01
 */
public class MyAopUtils {
    /**
     *  参数处理,超过指定长度字符的,只显示1000...
     * @author : 陈惟鲜 chenweixian
     * @Date : 2018年8月10日 上午11:44:11
     * @param paramStr
     * @param strlength
     * @return
     */
    public static String parameterHandle(String paramStr, int strlength){
        if (paramStr.length() > strlength){
            paramStr = paramStr.substring(0, strlength) + "...";
        }
        if (paramStr.length() > 10){
            paramStr = "[" + paramStr + "]";
        }
        return paramStr;
    }
    
    /***
     *  获取请求参数
     * @author : 陈惟鲜 chenweixian
     * @Date : 2018年8月9日 下午3:47:08
     * @param point
     * @return
     */
    public static String getRequestParam(ProceedingJoinPoint point){
        /**
         * 获取方法的参数值数组。
         */
        Object[] methodArgs = point.getArgs();
        
        // 结果
        String requestStr = "";
        /**
         * 获取方法参数名称
         */
         try {
            requestStr = logParam(methodArgs);
        } catch (Exception e) {
            requestStr = "获取参数失败";
        }
        return requestStr;
    }
    
//    /**
//     * 使用javassist来获取方法参数名称
//     * @param class_name    类名
//     * @param method_name   方法名
//     * @return
//     * @throws Exception
//     */
//    private String[] getFieldsName(String class_name, String method_name) throws Exception {
//        Class<?> clazz = Class.forName(class_name);
//        String clazz_name = clazz.getName();
//        ClassPool pool = ClassPool.getDefault();
//        ClassClassPath classPath = new ClassClassPath(clazz);
//        pool.insertClassPath(classPath);
//
//        CtClass ctClass = pool.get(clazz_name);
//        CtMethod ctMethod = ctClass.getDeclaredMethod(method_name);
//        MethodInfo methodInfo = ctMethod.getMethodInfo();
//        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
//        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
//        if(attr == null){
//            return null;
//        }
//        String[] paramsArgsName = new String[ctMethod.getParameterTypes().length];
//        int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
//        for (int i=0;i<paramsArgsName.length;i++){
//            paramsArgsName[i] = attr.variableName(i + pos);
//        }
//        return paramsArgsName;
//    }
    
    /**
     * 判断是否为基本类型:包括String
     * @param clazz clazz
     * @return  true:是;     false:不是
     */
    private static boolean isPrimite(Class<?> clazz){
        if (clazz.isPrimitive() || clazz == String.class){
            return true;
        }else {
            return false;
        }
    }


    /**
     * 打印方法参数值  基本类型直接打印,非基本类型需要重写toString方法
     * @param paramsArgsName    方法参数名数组
     * @param paramsArgsValue   方法参数值数组
     */
    private static String logParam(Object[] paramsArgsValue){
        if(ArrayUtils.isEmpty(paramsArgsValue)){
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        for (int i=0;i<paramsArgsValue.length;i++){
            //参数名
//            String name = paramsArgsName[i];
            //参数值
            Object value = paramsArgsValue[i];
//            buffer.append(name +" = ");
            if(isPrimite(value.getClass())){
                buffer.append(value + "  ,");
            }else {
                buffer.append(value.toString() + "  ,");
            }
        }
        return buffer.toString();
    }
}

 

 

修改后,原来的方法,自定义标签使用后,就很简单了。

    /**查询数据*/
    @RedisCacheAT
    public Object selectValue(String dicCode, String key) {
        Object result = dictionaryDao.getDicInfoValue(dicCode, key);
        return result;
    }

 

 

完。。。。。。。。。。。。。

posted on 2023-05-17 11:19  陈惟鲜的博客  阅读(208)  评论(0编辑  收藏  举报

导航