java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springboot+redis缓存方案

springboot+redis缓存的实现方案

作者:李晨豪 Lch

本文介绍了Spring Boot与Redis结合实现缓存的三种方案:注解方式、注解切面类方式和使用样例,通过这些方案,可以有效地提高应用程序的性能和响应速度

springboot+redis缓存方案

一、注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

/**
 * @author lch
 * @date 2023/8/03 09:29
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {

    /**
     * key,支持 spring el表达式
     */
    String key();

    /**
     * 统一格式:服务名:场景,如:info
     */
    String prefix();

    /**
     * 过期时间
     */
    int expireTime() default 36000;

    /**
     * 时间单位
     */
    TimeUnit timeunit() default TimeUnit.SECONDS;

}

二、注解切面类

import com.dewav.tms.framework.aspectj.lang.annotation.RedisCache;
import com.dewav.tms.framework.redis.RedisService;
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.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author lch
 * @date 2023/8/03 09:29
 */
@Component
@Aspect
@Slf4j
public class RedisCacheAspect {

    private final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();

    private final DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @Resource
    private RedisService redisService;

    @Around("@annotation(redisCache)")
    public Object queryByRedisCache(ProceedingJoinPoint pjp, RedisCache redisCache) {
        int expireTime = redisCache.expireTime();
        String key = redisCache.key();
        String prefix = redisCache.prefix();
        Assert.hasText(key, "@RedisCache key不能为空!");
        Assert.hasText(prefix, "@RedisCache prefix不能为空!");
        String evaluateExpression = evaluateExpression(key, pjp);

        String redisKey = prefix + evaluateExpression;
        Object obj = null;
        try {
            if (null != redisKey){
                if (redisService.hasKey(redisKey)){
                    obj = redisService.getCacheObject(redisKey);
                    return obj;
                }
            }
        } catch (Exception e) {
            log.error("从Redis获取"+redisKey+"失败:"+e.getMessage());
        }

        try{
            obj = pjp.proceed();
        }catch(Throwable e){
            log.error("执行异常", e);
            throw new RuntimeException(e.getMessage());
        }
        if (null != redisKey){
            redisService.setCacheObject(redisKey, obj, expireTime, TimeUnit.SECONDS);
        }

        return obj;
    }

    /**
     * 解析el表达式
     *
     * @param expression
     * @param point
     * @return
     */
    private String evaluateExpression(String expression, ProceedingJoinPoint point) {
        // 获取目标对象
        Object target = point.getTarget();
        // 获取方法参数
        Object[] args = point.getArgs();
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();

        EvaluationContext context = new MethodBasedEvaluationContext(target, method, args, parameterNameDiscoverer);
        Expression exp = spelExpressionParser.parseExpression(expression);
        return exp.getValue(context, String.class);
    }
}

三、使用样例

    @Override
    @RedisCache(key = "{#customerId + ':' + #dictType}", prefix = CacheConstants.SYS_DICT_KEY)
    public List<SysDictData> selectDictDataByType(Long customerId, String dictType) {
        return dictDataMapper.selectDictDataByType(customerId, dictType);
    }

	@Override
    @RedisCache(key = "#apiKey", prefix = CacheConstants.OPEN_KEY + "apiInfo:apiKey:")
    public EdiApiInfo getByApiKey(String apiKey) {
        return baseMapper.selectOne(new QueryWrapper<EdiApiInfo>()
                .eq("api_key", apiKey)
                .eq("status", true)
                .eq("del_flag", false));
    }

总结

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

您可能感兴趣的文章:
阅读全文