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

打造redis缓存组件

使用热插拔aop+反射+redis自定义注解+spring EL表达式打造redis缓存组件,优雅重构缓存代码

redis配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
@EnableAspectJAutoProxy //V2  开启AOP自动代理
public class RedisConfig
{/*** @param lettuceConnectionFactory* @return** redis序列化的工具配置类,下面这个请一定开启配置* 127.0.0.1:6379> keys ** 1) "ord:102"  序列化过* 2) "\xac\xed\x00\x05t\x00\aord:102"   野生,没有序列化过*/@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式jsonredisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRedisCache     //@EnableAspectJAutoProxy //启AOP自动代理
{//约等于键的前缀prefix,String keyPrefix();//SpringEL表达式,解析占位符对应的匹配value值String matchValue();
}

AOP

import jakarta.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
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 org.aspectj.lang.reflect.MethodSignature;import java.lang.reflect.Method;
import java.util.Objects;@Component
@Aspect
public class MyRedisCacheAspect
{@Resourceprivate RedisTemplate redisTemplate;//配置织入点@Pointcut("@annotation(com.atguigu.interview2.annotations.MyRedisCache)")public void cachePointCut(){}@Around("cachePointCut()")public Object doCache(ProceedingJoinPoint joinPoint){Object result = null;/***     @MyRedisCache(keyPrefix = "user",matchValue = "#id")*     public User getUserById(Integer id)*     {*         return userMapper.selectByPrimaryKey(id);*     }*/try{//1 获得重载后的方法名MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();//2 确定方法名后获得该方法上面配置的注解标签MyRedisCacheMyRedisCache myRedisCacheAnnotation = method.getAnnotation(MyRedisCache.class);//3 拿到了MyRedisCache这个注解标签,获得该注解上面配置的参数进行封装和调用String keyPrefix = myRedisCacheAnnotation.keyPrefix();String matchValueSpringEL = myRedisCacheAnnotation.matchValue();//4 SpringEL 解析器ExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(matchValueSpringEL);//#idEvaluationContext context = new StandardEvaluationContext();//5 获得方法里面的形参个数Object[] args = joinPoint.getArgs();DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0; i < parameterNames.length; i++){System.out.println("获得方法里参数名和值: "+parameterNames[i] + "\t" + args[i].toString());context.setVariable(parameterNames[i], args[i].toString());}//6 通过上述,拼接redis的最终key形式String key = keyPrefix + ":" + expression.getValue(context).toString();System.out.println("------拼接redis的最终key形式: " + key);//7 先去redis里面查询看有没有result = redisTemplate.opsForValue().get(key);if (result != null){System.out.println("------redis里面有,我直接返回结果不再打扰mysql: " + result);return result;}//8 redis里面没有,去找msyql查询或叫进行后续业务逻辑//-------aop精华部分,才去找findUserById方法干活//userMapper.selectByPrimaryKey(id);result = joinPoint.proceed();//主业务逻辑查询mysql,放行放行放行//9 mysql步骤结束,还需要把结果存入redis一次,缓存补偿if (result != null){System.out.println("------redis里面无,还需要把结果存入redis一次,缓存补偿: " + result);redisTemplate.opsForValue().set(key, result);}} catch (Throwable throwable) {throwable.printStackTrace();}return result;}
}

测试

    /*** 会将返回值存进redis里,key生成规则需要程序员用SpEL表达式自己指定,value就是程序从mysql查出并返回的user* redis的key 等于  keyPrefix:matchValue*/@Override@MyRedisCache(keyPrefix = "user",matchValue = "#id")public User getUserById(Integer id){return userMapper.selectByPrimaryKey(id);}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • CAN总线/CAN应用层协议设计,理解并实践仲裁段位域定义
  • vue vite创建项目步骤
  • 推荐系统实战(四)精排-交叉结构
  • 【第55课】XSS防御HttpOnlyCSP靶场工具等
  • 如何使用ssm实现游戏攻略网站的设计与实现+vue
  • 测试员阿聪的破局之路:从迷茫到帝都站稳脚跟,大佬亲授良方
  • 想学网络,为什么要先学数通?
  • 【图机器学习系列】(二)从传统机器学习角度理解图(一)
  • 正交试验法(或PICT)来设计测试用例
  • 如何使用ssm实现在线云音乐系统的设计与实现
  • 探索提示工程 Prompt Engineering的奥妙
  • 通过 OpenAI Embedding 接口计算相似度
  • 四川财谷通,信息科技引领者!
  • GAMES101——作业5 光线与三角形相交(菲涅尔反射率)
  • Java笔试面试题AI答之线程(11)
  • ECMAScript入门(七)--Module语法
  • spring学习第二天
  • vue-router的history模式发布配置
  • Vultr 教程目录
  • 创建一种深思熟虑的文化
  • 电商搜索引擎的架构设计和性能优化
  • 类orAPI - 收藏集 - 掘金
  • 怎么将电脑中的声音录制成WAV格式
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • #FPGA(基础知识)
  • #include
  • #include<初见C语言之指针(5)>
  • (libusb) usb口自动刷新
  • (二)Eureka服务搭建,服务注册,服务发现
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (四)Linux Shell编程——输入输出重定向
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转) 深度模型优化性能 调参
  • (转)Sql Server 保留几位小数的两种做法
  • .form文件_SSM框架文件上传篇
  • .net core docker部署教程和细节问题
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET 表达式计算:Expression Evaluator
  • .NET 常见的偏门问题
  • .NetCore发布到IIS
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • .NET学习教程二——.net基础定义+VS常用设置
  • /3GB和/USERVA开关
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • ??javascript里的变量问题
  • @Value读取properties中文乱码解决方案
  • [ Algorithm ] N次方算法 N Square 动态规划解决
  • [ 数据结构 - C++]红黑树RBTree
  • [.net]官方水晶报表的使用以演示下载
  • [2019.3.20]BZOJ4573 [Zjoi2016]大森林
  • [2019/05/17]解决springboot测试List接口时JSON传参异常
  • [2024-06]-[大模型]-[Ollama]- WebUI
  • [2024最新教程]地表最强AGI:Claude 3注册账号/登录账号/访问方法,小白教程包教包会