ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

自定义注解实现Redis缓存

2021-11-30 17:00:41  阅读:145  来源: 互联网

标签:缓存 String 自定义 Redis springframework pjp org import method


使用redis做缓存,很多情况下写的都是一样的模板代码,且代码侵入大,于是封装成注解,后面需要缓存的时候只需要加上注解就可以了,话不多说,都在代码里

注解定义:

CacheData

import java.lang.annotation.*;

/**
 * 注解 CacheData 用于简便处理需要进行缓存的操作
 * 注意 增加了全局缓存开关,参数为 global_cache_open_status_key,
 * 若是要关闭所有使用这个注解的缓存,可在nacos 配置中心或者其他配置文件配置 global_cache_open_status_key: false 即可关闭
 * 若是要关闭单个使用注解缓存的地方,在nacos 配置中心或者其他配置文件的地方 配置对应 prefix值: false 即可
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheData {

    /**
     * 前缀
     * @return
     */
    String prefix();

    /**
     * 后缀表达式,为空时候表示不需要后缀表达式,采用 SPEL
     * eg:
     *  1.不支持加固定后缀!!! 目前spEl数据源是来自方法入参,要是需要固定后缀,放置在前缀就好了;
     *  2.访问参数 比如 methodName(String userId, String pageId)  ->"#userId+'_'+#pageId";
     *  3.访问对象内属性 比如 methodName(UserBO userBO)  ->"#userBO.name";
     *  4.访问集合数据 比如 methodName(List<String> list) -> "#list.toString()";
     *
     * @return
     */
    String suffixExpression() default "";

    /**
     * 缓存时间 秒
     * @return
     */
    long expireSecond() default 300;


}

切面类:

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.sd.outbound.common.annotation.CacheData;
import com.sd.outbound.core.CoreConstants;
import com.soudian.common.StringHelper;
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.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Type;


@Slf4j
@Aspect
@Component
public class CacheDataAspect {

    private ExpressionParser parser = new SpelExpressionParser();

    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();


    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    private Environment env;

    @Around("@annotation(cacheData)")
    public Object cacheDataAround(ProceedingJoinPoint pjp, CacheData cacheData) throws Throwable {
        String key = cacheData.prefix();

        String currentCacheOpenStatus = env.getProperty(key);
        String globalCacheStatus = env.getProperty(CoreConstants.GLOBAL_CACHE_OPEN_STATUS_KEY);
        log.info("cacheOpenStatus of {} = {}, globalCacheStatus={}", key, currentCacheOpenStatus, globalCacheStatus);
        if(Boolean.FALSE.toString().toLowerCase().equals(globalCacheStatus) || Boolean.FALSE.toString().toLowerCase().equals(currentCacheOpenStatus)){
            return pjp.proceed();
        }

        long expireSecond = cacheData.expireSecond();
        Method method = getMethod(pjp);
        Type genericReturnType = method.getGenericReturnType();

        if(StringHelper.isNotEmpty(cacheData.suffixExpression())){
            key = StrUtil.join(StrUtil.COLON, key,  parseSpel(getMethod(pjp), pjp.getArgs(), cacheData.suffixExpression()));
        }
        String data = stringRedisTemplate.opsForValue().get(key);

        Object result = null;
        if(StringHelper.isNotEmpty(data)){
            result = JSON.parseObject(data, genericReturnType);
            log.info("CacheData get data from cache in method: {}", method.getName());
        }else {
            result = pjp.proceed();
            stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(result), expireSecond);
            log.info("CacheData get data from db in method:{}", method.getName());
        }

        return result;
    }

    private Object parseSpel(Method method, Object[] arguments, String spel) {
        String[] params = discoverer.getParameterNames(method);
        EvaluationContext context = new StandardEvaluationContext();
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], arguments[len]);
        }
        try {
            Expression expression = parser.parseExpression(spel);
            return expression.getValue(context);
        } catch (Exception e) {
            return StrUtil.EMPTY;
        }
    }

    private static Method getMethod(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        if (method.getDeclaringClass().isInterface()) {
            try {
                method = pjp
                        .getTarget()
                        .getClass()
                        .getDeclaredMethod(pjp.getSignature().getName(),
                                method.getParameterTypes());
            } catch (SecurityException | NoSuchMethodException e) {
                throw new RuntimeException(e);
            }
        }

        return method;
    }
}

使用:

    @CacheData(prefix = "user_authority", suffixExpression = "#userId+'_'+#pageId")
    public List<String> getUserIdDataAuthority(String userId,Long pageId){
       ...业务代码... 
}

 

OK.

 

标签:缓存,String,自定义,Redis,springframework,pjp,org,import,method
来源: https://www.cnblogs.com/heisehenbai/p/15624971.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有