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

devtools/2025/2/12 19:57:36/

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 {@Resourceprivate 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 keyString key = keyPrefix + ":" + expression.getValue(context).toString();//查询redisres = 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.ppmy.cn/devtools/158299.html

相关文章

electron.vite 项目创建以及better-sqlite3数据库使用

1.安装electron.vite npm create quick-start/electronlatest中文官网&#xff1a;https://cn.electron-vite.org/ 2. 安装项目依赖 npm i3.修改 electron-builder 配置文件 appId: com.electron.app productName: text33 directories:buildResources: build files:- !**/.v…

在ArcGIS JS API中使用WebGL实现波纹扩散特效

在现代WebGIS开发中&#xff0c;ArcGIS JS API 是一个非常强大的工具&#xff0c;它允许开发者创建丰富的地理信息应用。结合WebGL技术&#xff0c;我们可以实现更加复杂和炫酷的可视化效果。本文将介绍如何使用ArcGIS JS API结合WebGL实现一个波纹扩散特效。 波纹扩散效果 1 概…

Rust 文件读取:实现我们的 “迷你 grep”

1. 准备示例文件 首先&#xff0c;在项目根目录&#xff08;与 Cargo.toml 同级&#xff09;下新建一个名为 poem.txt 的文件。示例内容可参考 Emily Dickinson 的诗&#xff1a; Im nobody! Who are you? Are you nobody, too? Then theres a pair of us — dont tell! Th…

请解释 JavaScript 中的函数式编程,优缺点是什么?

一、对JavaScript函数式编程的理解 函数式编程&#xff08;Functional Programming&#xff0c;FP&#xff09;是一种编程范式&#xff0c;它将计算视为数学函数的求值&#xff0c;并避免改变状态和可变数据。 在JavaScript中&#xff0c;函数式编程具有以下几个关键特性&…

使用epoll与sqlite3进行注册登录

将 epoll 服务器 客户端拿来用 客户端&#xff1a;写一个界面&#xff0c;里面有注册登录 服务器&#xff1a;处理注册和登录逻辑&#xff0c;注册的话将注册的账号密码写入数据库&#xff0c;登录的话查询数据库中是否存在账号&#xff0c;并验证密码是否正确 额外功能&…

fastadmin图片前台导出

参考 https://github.com/hhurz/tableExport.jquery.plugin#options define([jquery, bootstrap, backend, table, form], function ($, undefined, Backend, Table, Form) {$(document).ready(function(){$(#table).bootstrapTable(refreshOptions, {exportOptions: {onMsoNu…

体验 DeepSeek-R1:解密 1.5B、7B、8B 版本的强大性能与应用

文章目录 &#x1f34b;引言&#x1f34b;DeepSeek 模型简介&#x1f34b;版本更新&#xff1a;1.5B、7B、8B 的区别与特点&#x1f34b;模型评估&#x1f34b;体验 DeepSeek 的过程&#x1f34b;总结 &#x1f34b;引言 随着大规模语言模型的持续发展&#xff0c;许多模型在性…

Node.js 实现简单爬虫

介绍 爬虫是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。 本文将使用 Nodejs 编写一个简单的爬虫脚本&#xff0c;爬取一个美食网站&#xff0c;获取菜品的标题和图片链接&#xff0c;并以表格的形式输出。 准备工作 1、初始化项目 首先&#xff0…