springboot+redis缓存的实现方案

 更新时间:2025年03月05日 09:33:24   作者:李晨豪 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));
    }

总结

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

相关文章

  • Java设计模式之动态代理

    Java设计模式之动态代理

    今天小编就为大家分享一篇关于Java设计模式之动态代理,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • JAVA 格式化日期、时间的方法

    JAVA 格式化日期、时间的方法

    这篇文章主要介绍了JAVA 格式化日期、时间的方法,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • 基于Java回顾之多线程同步的使用详解

    基于Java回顾之多线程同步的使用详解

    在这篇文章里,我们关注线程同步的话题。这是比多线程更复杂,稍不留意,我们就会“掉到坑里”,而且和单线程程序不同,多线程的错误是否每次都出现,也是不固定的,这给调试也带来了很大的挑战
    2013-05-05
  • SpringBoot web静态资源配置详解

    SpringBoot web静态资源配置详解

    这篇文章主要介绍了SpringBoot web静态资源配置详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Spring Session的使用示例

    Spring Session的使用示例

    最近团队一个项目需要使用Session,之前没有在实际项目中使用过Spring-Session,这里记录一下使用的过程
    2021-06-06
  • 五种SpringBoot实现数据加密存储的方式总结

    五种SpringBoot实现数据加密存储的方式总结

    这篇文章主要为大家详细介绍了五种常见数据加密存储的方法(结合SpringBoot和MyBatisPlus框架进行实现),文中的示例代码讲解详细,需要的可以参考下
    2023-11-11
  • Pulsar负载均衡原理及优化方案详解

    Pulsar负载均衡原理及优化方案详解

    这篇文章主要为大家介绍了Pulsar负载均衡原理及优化方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • k8s+springboot+CronJob定时任务部署实现

    k8s+springboot+CronJob定时任务部署实现

    本文主要介绍了k8s+springboot+CronJob定时任务部署实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Java单例模式的8种写法(推荐)

    Java单例模式的8种写法(推荐)

    这篇文章主要介绍了Java单例模式的8种写法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • Java实现学生成绩管理系统

    Java实现学生成绩管理系统

    这篇文章主要为大家详细介绍了Java实现学生成绩管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04

最新评论