当前位置: 首页 > article >正文

【场景题】架构优化 - 解耦Redis缓存与业务逻辑

1. 需求分析

某公司需要将原有的Redis缓存抽离出来,并且还要要实现:

  1. 可配置
  2. 热拔插
  3. 高可用
  4. 高通用

请问你会如何实现?

2. 思路

话不多说直接上思路:

  1. 自定义缓存注解,当容器扫描到该注解自动调用AOP想应的增强方法为原有的业务逻辑赋能
  2. 使用SpringEL表达式占位符扩展

3. 代码实现

3.1 注解创建

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRedisCatch {
    // 前缀
    String keyPrefix();
    // 匹配的value值
    String matchValue();
}

3.2 切面类

@Component
@Aspect
public class MyRedisCacheAspect {
    @Resource
    private RedisTemplate redisTemplate;
    //换成自己注解的全类名
    @Around("@annotation(com.example.redisexercises.annotation.MyRedisCatch)")
    public Object doCatch(ProceedingJoinPoint joinPoint){
        Object res = null;

        try {
            //获取当前的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            //获取方法上的注解
            MyRedisCatch redisCatchAnnotation = method.getAnnotation(MyRedisCatch.class);
            //获得注解中的参数
            String keyPrefix = redisCatchAnnotation.keyPrefix();
            String matchValue = redisCatchAnnotation.matchValue();

            //SpringEL解析器
            SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
            Expression expression = spelExpressionParser.parseExpression(matchValue);
            EvaluationContext context = new StandardEvaluationContext();

            //获得方法中形参
            Object[] args = joinPoint.getArgs();
            DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(method);
            for(int i = 0;i< parameterNames.length;i++){
                context.setVariable(parameterNames[i], args[i].toString());
            }

            //拼接最终redis key
            String key = keyPrefix + ":" + expression.getValue(context).toString();

            //查询redis
            res = redisTemplate.opsForValue().get(key);
            if(res != null){
                return res;
            }
			//没查询到结果则则主业务类查数据库
            res = joinPoint.proceed();
            //最终回填到redis中,下次查询命中
            if(res != null)
                redisTemplate.opsForValue().set(key, res, 60, TimeUnit.SECONDS);
        }catch (Throwable throwable){
            throwable.printStackTrace();
        }

        return res;
    }
}

3.3 在任意方法上标注注解以实现缓存功能

@ApiOperation("获取商品")
@GetMapping("/get/{id}")
@MyRedisCatch(keyPrefix = "user", matchValue = "id")
public Order get(@PathVariable Integer id){
    //数据库查找业务逻辑
}

http://www.kler.cn/a/537726.html

相关文章:

  • [LeetCode]day16 242.有效的字母异位词
  • CNN-day5-经典神经网络LeNets5
  • BUU30 [网鼎杯 2018]Fakebook1
  • Vite 为什么快,是怎么打包的
  • 如何删除本地大模型
  • 小哆啦探秘《JavaScript高级程序设计》
  • LLM:DeepSeek 系列(三)
  • 【代码随想录|子序列系列300,674,718】
  • Qwen2-VL:增强视觉语言模型对世界任意分辨率的感知能力
  • 如何使用DeepSeek
  • mybatis 是否支持延迟加载?延迟加载的原理是什么?
  • systemverilog的program和module的区别
  • ReentrantLock/内存溢出监控
  • 南京观海微电子----开关电源电路图
  • Java_方法引用
  • leetcode——杨辉三角(简单移动的解法)
  • 后台管理系统网页开发
  • deepseek搭建本地知识库
  • 基于大模型的围术期脆弱性评估系统研究报告
  • 软考通过率仅有10% ?或许2025年更难?
  • 训练你的模型:如何构造和优化训练数据(三·上)
  • PAT乙级( 1009 说反话 1010 一元多项式求导)C语言版本超详细解析
  • WordPress email-subscribers插件存在SQL注入漏洞(CVE-2024-2876)
  • Java中实现‌‌SHA-3算法介绍、应用场景和示例代码
  • 21.2.6 字体和边框
  • DeepSeek V3报告阅读