AOP+ 自定义注解 +SpringElExpress自研缓存组件

news2024/12/23 14:25:42

AOP+ 自定义注解 +SpringElExpress自研缓存组件

    • 背景
    • 前置知识
    • 改造代码

背景

思考下这段代码,想想项目中是不是到处存在
先查缓存,缓存里面有,直接返回;缓存没有,查数据库,并更新到缓存
思考:如何将缓存代码从业务代码中剥离,促使业务代码更简洁更易维护,可以把这部分通过AOP来统一处理
在这里插入图片描述

前置知识

提前预习一波 SpringEL 表达式
在这里插入图片描述

改造代码

首先配置

spring.datasource.url=jdbc:mysql://192.168.133.128:3306/wxpay?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.mapper-locations=classpath*:mapper/*.xml

spring.data.redis.database=0
spring.data.redis.host=192.168.133.128
spring.data.redis.port=6379
spring.data.redis.password=123456
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1ms
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0

注解和切面定义

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface MyRedisCacheAnnotation {
    String keyPrefix();

    String matchValue();
}
@Slf4j
@Aspect
@Component
public class MyRedisCacheAspect {
    @Resource
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.example.demo.annotation.MyRedisCacheAnnotation)")
    public void cachePointCut() {}

    @Around("cachePointCut()")
    public Object doCache(ProceedingJoinPoint pjp) {
        Object result = null;
        try {
            // 获得重载后的方法名
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            Method method = signature.getMethod();
            // 确定方法名后获得该方法上面的注解标签 MyRedisCacheAnnotation
            MyRedisCacheAnnotation annotation = method.getAnnotation(MyRedisCacheAnnotation.class);
            // 获取注解上配置的参数
            String keyPrefix = annotation.keyPrefix();
            String matchValue = annotation.matchValue();

            // SpringEL 解析器
            SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
            Expression expression = spelExpressionParser.parseExpression(matchValue); // #id
            StandardEvaluationContext context = new StandardEvaluationContext();
            // 获得方法的形参个数
            Object[] args = pjp.getArgs();
            DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
            String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
                log.info("方法参数名称:{}, 值:{}", parameterNames[i], args[i].toString());
                context.setVariable(parameterNames[i], args[i].toString());
            }
            // 拼接 redis 的最终 key 形式
            String key = keyPrefix + ":" + expression.getValue(context).toString();
            log.info("key形式{}", key);
            // 先去 redis 看看有没有
            result = redisTemplate.opsForValue().get(key);
            if (result != null) {
                log.info("redis里有,直接返回了");
                return result;
            }
            result = pjp.proceed();
            if (result != null) {
                redisTemplate.opsForValue().set(key, result);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return result;
    }
}

不要忘了重写 redisTemplate

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

最后 service 层的效果,简便多了是不是

@Autowired
private UserMapper userMapper;

@Override
@MyRedisCacheAnnotation(keyPrefix="user", matchValue="#id")
public User getUserById(Integer id) {
    return userMapper.selectById(id);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2062138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

你遇到过哪些触发NPE的代码场景?

你遇到过哪些触发NPE的代码场景&#xff1f; NPE如何处理NPE 在Java编程实践中&#xff0c;空指针异常&#xff08;NPE&#xff09;是开发过程中常见的障碍&#xff0c;它不仅阻碍了代码的正常运行&#xff0c;还常常成为系统不稳定性的根源。那么如何识别那些潜藏于代码深处的…

6个你应该尝试Lens.org的理由:一个免费的文献可视化和专利网站

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 最近发现的一个免费的文献检索工具Lens.org介绍给大家&#xff0c;相比其他文献检索工具web of science、Scopus等&#xff0c;独到之处在于它对于搜索结果全面的可视化呈现效…

ubuntu右上角没有小键盘图标

这个比较奇怪&#xff0c;一开始好好的&#xff0c;用着用着就不行了。网上解决方案比较多&#xff0c;大多数能解决一部分问题。 1.设置“输入法系统” 2.在终端运行 sudo killall ibus-daemon&#xff08;结束进程&#xff09; bus-daemon -d&#xff08;重启ibus&#xff0…

Go之函数

一、函数基本使用 一&#xff09;函数概述 1、函数定义 对特定的功能进行提取&#xff0c;形成一个代码片段 2、函数的作用 提高代码的复用性&#xff0c;减少代码的冗余&#xff0c;代码的维护性也提高了 3、函数中间的关系 函数与函数是并列关系&#xff0c;所以定义的函数不…

Secure Coding in C and C ++ (四)局部静态构造函数 虚函数

前言 上一章节我们讲解了 关于C静态和指针与引用的部分 我们先来回顾一下相关的内容&#xff1a; 指针说白了就是地址&#xff0c; int a; int * ptr &a这里的整形指针 就是存放的整数变量的地址 静态 static 有两种层面&#xff1a; 第一种层面就是在其他的文件里&…

Ansys Zemax|如何自定义优化操作数

虽然Zemax OpticStudio有300多个内建优化操作数&#xff0c;但是还是会有一些特殊情况是这300多个操作数无法涵盖的。这就要求使用者根据要求计算出某些特定的数值&#xff0c;将这些数值返回到某个操作数&#xff0c;再对此操作数进行优化。 Zemax OpticStudio支持用户编程&a…

【SpringCloud】(一文通)多机部署, 负载均衡-LoadBalance

目 录 一. 负载均衡介绍1.2 什么是负载均衡1.3 负载均衡的⼀些实现 二. Spring Cloud LoadBalancer2.1 快速上手2.1.1 使用 Spring Cloud LoadBalancer 实现负载均衡2.1.2 启动多个product-service实例 2.2 负载均衡策略2.3 LoadBalancer 原理 三. 服务部署(Linux)3.2 服务构建…

(24)(24.4) MultiWii/DJI/HDZero OSD (version 4.2 and later)(一)

文章目录 前言 1 基于遥测的OSD 前言 ArduPilot 使用基于MSP&#xff08;MultiWii 串行协议&#xff09;的协议支持多种类型的屏幕显示&#xff08;OSD&#xff09;&#xff1a; 基于 MSP 遥测的操作系统&#xff0c;如大疆 FPV 护目镜 V1/V2、大疆护目镜 RE、FatShark Byte…

QML----QML+VTK+CMake示例

为了创建一个使用QML和VTK的示例项目,并使用CMake进行构建,将遵循以下步骤: 创建C++类以集成VTK和QML:这个类将负责设置VTK渲染数据,并与QML进行交互。设置CMake配置:配置CMake以找到并链接Qt和VTK库。创建QML界面:设计QML界面以显示VTK渲染的内容。编写主函数:初始化应…

C语言实现通讯录-动态版本与文件版本

C语言实现通讯录-动态版本与文件版本 1.前言2.动态版本2.1联系人信息之前的&#xff1a;改版: 2.2初始化之前的&#xff1a;改版&#xff1a; 2.3自动扩容 3.文件版本3.1自动保存函数实现&#xff1a;效果&#xff1a; 3.2打开时加载信息函数实现&#xff1a;效果&#xff1a; …

day37-https实战

1.知识点补充: 四层代理转发数据库 目的: 通过10.0.0.4 使用ssh远程连接到web01 ssh--->10.0.0.4:2222 ---------->172.16.1.7:22 xshell-->创建会话-->10.0.0.4 端口 2222 Linux系统 ssh 10.0.0.4 -p2222作业: 目的: 实现连接10.0.0.4的5555端口转发到后端数据库…

【hot100篇-python刷题记录】【只出现一次的数字】

R5-技巧篇 思路&#xff1a;使用哈希记录次数即可 class Solution:def singleNumber(self, nums: List[int]) -> int:dictdefaultdict(int)for num in nums:dict[num]1for num in nums:if dict[num]1:return num

【hot100篇-python刷题记录】【爬楼梯】

R5-真正的动态规划 动态规划核心&#xff1a; 第i步是怎么来的&#xff08;即动态规划公式&#xff09; 走到第i步阶梯的总方法数sum(走到第i-1步阶梯的总方法数&#xff0c;走到第i-2步阶梯的总方法数) class Solution:def climbStairs(self, n: int) -> int:if n<2:r…

云原生系列 - Nginx(高级篇)

前言 学习视频&#xff1a;尚硅谷Nginx教程&#xff08;亿级流量nginx架构设计&#xff09;本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删学习文档&#xff1a; 云原生系列 - Nginx(基础篇)云原生系列 - Nginx(高级篇) 一、扩容 通过扩容提升整体吞吐量…

OpenCV resize 的各插值方式的区别与用途

一、resize 函数中 interpolation 参数的区别和用途 cv2.resize 函数中的 interpolation 参数用于指定图像缩放时使用的插值方法。不同的插值方法会影响缩放后图像的质量和处理速度。以下是cv2.INTER_AREA、cv2.INTER_CUBIC、cv2.INTER_NEAREST、cv2.INTER_LINEAR 和 cv2.INTE…

有关应用层面试题有关库的思维导体

面试题目&#xff1a; TCP通信中3次握手和四次挥手&#xff1f; 答&#xff1a; 第一次握手&#xff1a;客户端发送SYN包&#xff08;SYN1, seq0&#xff09;给服务器&#xff0c;并进入SYN_SENT状态&#xff0c;等待服务器返回确认包。第二次握手&#xff1a;服务器接收到S…

什么是Redis大key问题?如何解决?

目录 Key多大算大呢&#xff1f; 识别big key 处理big key Big Key是Redis中存储了大量的数据的Key&#xff0c;不要误以为big key只是表示Key的值很大&#xff0c;他还包括这个Key对应的value占用空间很多的情况&#xff0c;通常在String、list、hash、set、zset等类型中出…

三、Socket多路复用介绍

一、Socket连接方式 二、多路复用 三、Socket连接包含的内容

搭建TestBench,收藏这几条基本框架就够了

Verilog功能模块HDL设计完成后&#xff0c;并不代表设计工作的结束&#xff0c;还需要对设计进行进一步的仿真验证。掌握验证的方法&#xff0c;即如何调试自己的程序非常重要。在RTL逻辑设计中&#xff0c;要学会根据硬件逻辑来写测试程序即写Testbench。Verilog测试平台是一个…

MATLAB中qr函数用法

目录 语法 说明 示例 Q-Less QR 分解 矩阵的完整 QR 分解 置换 QR 分解 用精简 QR 因子求解线性系统 求解稀疏线性系统 求解矩形稀疏线性系统 提示 qr函数的功能是对矩阵进行QR 分解。 语法 R qr(A) [Q,R] qr(A) [Q,R,P] qr(A) [___] qr(A,"econ") […