注解与AOP切面编程实现redis缓存与数据库查询的解耦
一般缓存与数据库的配合使用是这样的。
1.查询缓存中是否有数据。
2.缓存中无数据,查询数据库。
3.把数据库数据插入到缓存中。
其实我们发现 1,3 都是固定的套路,只有2 是真正的业务代码。我们可以把1,3 抽取出来,封装到一个自定义注解@myCache 上,通过给2方法加一个注解,实现代码的解耦。
package com.itbac.common.cache; import org.springframework.stereotype.Service; @Service
public class SkuQueryService {
//注解的使用
@myCache(key = "'SkuQueryService_findById' + #id")
public Object findById(String id){ System.out.println("findById方法查询数据库"); return "数据库返回值:"+id;
}
}
自定义注解
package com.itbac.common.cache; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; // 注解的生命周期:运行时
@Retention(RetentionPolicy.RUNTIME)
// 注解的应用范围:修饰方法
@Target(ElementType.METHOD)
public @interface myCache {
/**
* key 的生成规则,通过springEL表达式
* @return
*/
String key();
}
AOP切面类,切面编程,动态解析注解。
package com.itbac.common.cache; 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.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component; import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit; /**
* Aop切面编程
*/
@Component
@Aspect
public class cacheAOP { @Autowired
private RedisTemplate redisTemplate;
// 环绕通知 : 监控自定义注解 。
@Around("@annotation(com.itbac.common.cache.myCache)")
public Object doAnyThing(ProceedingJoinPoint joinPoint) throws Throwable {
String key =null;
//1.反射技术:从注解里里面,读取key的生成规则。
//1.1 从切入点,获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//1.2 从切点,获取目标对象的字节码,的方法。参数:(方法名,方法的所有参数)。
Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes());
//1.3 从方法获取注解。
myCache annotation = method.getAnnotation(myCache.class);
//1.4 从注解,获取注解信息。'SkuQueryService_findById' + #id
String keyEL = annotation.key(); //2. 创建 springEL表达式 解析器
SpelExpressionParser parser = new SpelExpressionParser();
// 解析器 获取指定表达式 'SkuQueryService_findById' + #id 的表达式对象
Expression expression = parser.parseExpression(keyEL);
// 设置解析上下文
StandardEvaluationContext context = new StandardEvaluationContext();
//2.1 创建默认参数名 发现者
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
//2.2 获取方法中的所有参数名。
String[] parameterNames = discoverer.getParameterNames(method);
//2.3 获取切点方法中的所有参数值。
Object[] args = joinPoint.getArgs();
for (int i = 0; i < parameterNames.length; i++) {
// 把参数名,参数值,设置到解析器上下文
context.setVariable(parameterNames[i],args[i].toString());
}
//表达式 匹配 解析上下文 中的内容 ,拿到key
key = expression.getValue(context).toString(); Object o = redisTemplate.opsForValue().get(key);
if (o !=null){
// 缓存中有数据,直接返回。
//查询缓存
System.out.println("查询缓存返回。");
//延迟缓存失效时间,1天。
redisTemplate.expire(key,1,TimeUnit.DAYS);
return o;
}
// 缓存穿透标记
Object penetrateFlag = redisTemplate.opsForValue().get(key + "penetrateFlag");
if (null == penetrateFlag){
// 没有防止 缓存穿透标记,查数据库。 // 执行切点 中的代码,查询数据库。
Object proceed = joinPoint.proceed(); if (null == proceed){
// 数据库数据为空,设置缓存穿透标记。15分钟
redisTemplate.opsForValue().set(key + "penetrateFlag",true,15,TimeUnit.MINUTES);
}else {
// 数据库数据不为空,把数据存到缓存中。缓存1天。
redisTemplate.opsForValue().set(key,proceed,1, TimeUnit.DAYS);
}
return proceed ;
}
// 延迟缓存失效时间 15分钟 缓存穿透标记
redisTemplate.expire(key+"penetrateFlag",15,TimeUnit.MINUTES);
// 返回
return null;
}
}
这样就可以通过一个自定义注解@myCache ,实现了缓存与业务代码的解耦。其中还包含了防止缓存穿透的使用技巧。不要告诉别人哦。
注解与AOP切面编程实现redis缓存与数据库查询的解耦的更多相关文章
- SpringBoot 通过自定义注解实现AOP切面编程实例
一直心心念的想写一篇关于AOP切面实例的博文,拖更了许久之后,今天终于着手下笔将其完成. 基础概念 1.切面(Aspect) 首先要理解‘切’字,需要把对象想象成一个立方体,传统的面向对象变成思维,类 ...
- 注解配置AOP切面编程
1.导入先关jar包 2.编写applicationContext.xml,配置开启注解扫描和切面注解扫描 <?xml version="1.0" encoding=&quo ...
- 基于SpringBoot AOP面向切面编程实现Redis分布式锁
基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...
- AOP切面编程在android上的应用
代码地址如下:http://www.demodashi.com/demo/12563.html 前言 切面编程一直是一个热点的话题,这篇文章讲讲一个第三方aop库在android上的应用.第三方AOP ...
- SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...
- 十:SpringBoot-配置AOP切面编程,解决日志记录业务
SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...
- Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入
首选需要参考的是:[参考]http://www.cnblogs.com/guokai870510826/p/5977948.html http://www.cnblogs.com/guokai8 ...
- Spring AOP 切面编程记录日志和接口执行时间
最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特 ...
- 本地缓存,Redis缓存,数据库DB查询(结合代码分析)
问题背景 为什么要使用缓存?本地缓存/Redis缓存/数据库查询优先级? 一.为什么要使用缓存 原因:CPU的速度远远高于磁盘IO的速度问题:很多信息存在数据库当中的,每次查询数据库就是一次IO操作所 ...
随机推荐
- Codeforces Round #565 (Div. 3) B
B. Merge it! 题目链接:http://codeforces.com/contest/1176/problem/B 题目 You are given an array a consistin ...
- Kafka集群部署指南
一.前言 1.Kafka简介 Kafka是一个开源的分布式消息引擎/消息中间件,同时Kafka也是一个流处理平台.Kakfa支持以发布/订阅的方式在应用间传递消息,同时并基于消息功能添加了Kafka ...
- Git使用小技巧之Stash命令藏储零乱分支
想要获取更多文章可以访问我的博客 - 代码无止境. 在开发的过程中可能会经常出现下面这种情况,我们正在开发某个功能,当前分支的内容比较乱,不太适合提交,而此时我们需要切换到其他分支上处理一些事情.这 ...
- DRF 版本、认证、权限、限制、解析器和渲染器
目录 一.DRF之版本控制 为什么要有版本控制? DRF提供的版本控制方案 版本的使用 全局配置 局部配置(使用较少) 二.DRF之认证 内置的认证 步骤 三.DRF之权限 1.自定义一个权限类 2. ...
- ServiceFabric极简文档-4.1 学习路线图
Service Fabric学习路线图 原文地址:Service Fabric学习路线图
- 一道简单的for循环面试题(数字龙形排序)
本道题是我从网上见到的,因为是一道很久没做的循环题,自己的思路也是陷入了一些思维陷阱中,后来经过把大脑放空,重新看这道题后,思路立马就出来了. 题目就是完成如下图所示的效果: 我一开始是想着将它按照奇 ...
- 【深搜(DFS)-例题-踏青】-C++
描述 小白和他的朋友周末相约去召唤师峡谷踏青.他们发现召唤师峡谷的地图是由一块一块格子组成的,有的格子上是草丛,有的是空地.草丛通过上下左右 4 个方向扩展其他草丛形成一片草地,任何一片草地中的格子都 ...
- tomcat不需要重启热部署xml文件
项目中,遇到情况,有时候增加struts的配置了,有时候粗心改错了,然后急需要发布线上吧,又不能重启影响其他的,最后发现struts有这个功能呢! 在struts.xml的配置文件中加上一句话就行 & ...
- Intel FPGA 专用时钟引脚是否可以用作普通输入,输出或双向IO使用?
原创 by DeeZeng FPGA 的 CLK pin 是否可以用作普通输入 ,输出或双向IO 使用? 这些专用Clock input pin 是否可以当作 inout用,需要看FPGA是否支 ...
- jenkins +Jmeter 完成分布式性能测试
1.Jmeter 压测机器配置. 下载Jmeter 版本:https://jmeter.apache.org/download_jmeter.cgi 我下的是5.1.1 将下载后的版本进行解压. ...