redis结合自定义注解实现基于方法的注解缓存,及托底缓存的实现
本次分享如何使用redis结合自定义注解实现基于方法的注解缓存,及托底缓存的实现思路
现在的互联网公司大多数都是以Redis作为缓存,使用缓存的优点就不赘述了,写这篇文章的目的就是想帮助同学们如何在工作中更好的去实现缓存
目标
在方法上使用注解,实现如果标注了注解的方法会优先走缓存,如果命中缓存则返回缓存中的数据,如果没有命中缓存就穿透到方法中执行方法,然后将方法的返回值存储到缓存中,然后下次就可以在缓存设置的有效时间内从缓存中读取数据了
实现步骤
自定义注解
定义aop切面
思路:
如果方法标注了@CacheProfiler注解则走aop
如果获取到CacheProfiler类,并且readFromCache()设置的是true,就去getCacheKey()获取缓存的key
根据缓存的key值去redis中查询,如果有就查询缓存,如果没有就执行方法,将方法的返回值作为value存入缓存,并根据CacheProfiler的expire()设置的过期时间给key加上过期时间
自定义注解
/*** @Description:* @author: chenmingyu* @date: 2018/5/17 20:37*/@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface CacheProfiler {String cacheKey();int expire() default 60;boolean readFromCache() default true;}
讲解下代码:
@interface来修饰一个注解
cacheKey() 缓存key的前缀,缓存key由key前缀+入参组成,详见getCacheKey()方法
expire() 缓存的过去时间,默认为60秒
readFromCache() 是否读取缓存,默认为true
定义aop切面
@Pointcut("@annotation(org.my.cache.annotation.CacheProfiler)")public void cachePoint() {}@Around("cachePoint()")public Object beforeExec(ProceedingJoinPoint joinPoint) {Object obj = null;try {//获取方法Method method = this.getMethod(joinPoint);CacheProfiler cacheProfiler = (CacheProfiler) method.getAnnotation(CacheProfiler.class);//方法上没有注解,直接执行方法然后返回if (null == cacheProfiler) {return joinPoint.proceed();}//缓存keyString cacheKey = this.getCacheKey(joinPoint, cacheProfiler);//true:从缓存读if (cacheProfiler.readFromCache()) {obj = jedis.get(cacheKey);} else {return joinPoint.proceed();}if (null == obj) {obj = joinPoint.proceed();}else{return obj;}if (null != obj) {jedis.setex(cacheKey,cacheProfiler.expire(), JSONObject.toJSONString(obj));}return obj;} catch (Throwable throwable) {throwable.printStackTrace();}return obj;}
讲解下代码:
@Pointcut定义切入点为@CacheProfiler注解 @Around表示使用@CacheProfiler注解的方法将走环绕通知 getMethod(JoinPoint jp)获取目标方法 getCacheKey(ProceedingJoinPoint jp, CacheProfiler cacheProfiler) 获取缓存的key
获取CacheProfiler的方法
//获取方法private Method getMethod(JoinPoint jp) throws Exception {MethodSignature msig = (MethodSignature) jp.getSignature();Method method = msig.getMethod();return method;}
获取缓存的key的方法
private String getCacheKey(ProceedingJoinPoint jp, CacheProfiler cacheProfiler) {StringBuilder sb = new StringBuilder(cacheProfiler.cacheKey());if (jp.getArgs() != null && jp.getArgs().length != 0) {Object[] arr$ = jp.getArgs();int len$ = arr$.length;for (int i$ = 0; i$ < len$; ++i$) {Object obj = arr$[i$];if (obj != null) {sb.append("_").append(String.valueOf(obj));}}return sb.toString();} else {return sb.toString();}}
这个demo只是大概写了下,不过也可以实现本文的目标了,通过在方法上使用@CacheProfiler注解实现缓存,通过@CacheProfiler注解的相应参数去实现缓存属性的相关设置
写个Controller测试下
/*** @Description:* @author: chenmingyu* @date: 2018/5/20 11:18*/@RestControllerpublic class CacheController {@RequestMapping("/getUser")@CacheProfiler(cacheKey = "USER_CACHE_KEY",expire = 3*60,readFromCache = true)public List<User> getUser(Integer type){List<User> users = new ArrayList<>();if(type==1){User user = new User("明羽",24,"北京");users.add(user);}else if(type==2){User user = new User("小娜",24,"北京");users.add(user);}return users;}}
以上就实现了注解缓存,
托底缓存的实现
托底缓存的实现也很简单,首先说下可能需要托底缓存的场景,就比如一个电商网站,去获取商品列表,结果调用接口的时候出错了,这个时候又不希望网站的页面出现天窗【天窗的意思就是网站的页面上由于没获取到数据出现空白区域】,这个时候就需要托底数据了,即如果接口出现异常,也可以返回数据,【就是托底数据】
思路
可以给CacheProfiler注解加一个属性是否读取托底缓存 属性为boolean
然后在joinPoint.proceed()的时候加上try-cache,
如果执行方法的时候报异常了,并且上面那个是否读取托底缓存属性为true,就去缓存中读取托底数据
一般的代码中都会try-cache,如果在方法里已经捕获了异常,这就需要在执行的方法里去主动的抛异常,让aop切面可以捕获异常
其中重要的一点就是托底数据什么时候去存,这个可以在每次去存缓存的时候去存一份托底数据,或者定义一些存储策略,托底数据与缓存的数据可以定义为key的前缀不同【其实这个可以存成hash类型的数据,定义一个固定的key为托底数据的key【hash的key】,然后field为缓存的key】
具体的代码就不写,有思路就好实现了,各位同学可以自己去实现
感觉写的还有点干货就关注我的公众号啊
不定期分享优质文章
redis结合自定义注解实现基于方法的注解缓存,及托底缓存的实现的更多相关文章
- springboot基于方法级别注解事务的多数据源切换问题
springBoot多数据源配置 配置读数据源 @Component @ConfigurationProperties(prefix = "jdbc.read") @Propert ...
- Spring_day03--课程安排_基于aspectj的注解aop_Spring的jdbcTemplate操作
Spring_day03 上节内容回顾 今天内容介绍 基于aspectj的注解aop Spring的jdbcTemplate操作 增加 修改 删除 查询 Spring配置c3p0连接池和dao使用jd ...
- 002-spring cache 基于声明式注解的缓存-02-CachePut、CacheEvict、Caching、CacheConfig、EnableCaching、自定义
1.2.CachePut annotation 在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素 ...
- 在struts2.3.4.1中使用注解、反射、拦截器实现基于方法的权限控制
权限控制是每一个系统都应该有的一个功能,有些只需要简单控制一下就可以了,然而有些却需要进行更加深入和细致的权限控制,尤其是对于一些MIS类系统,基于方法的权限控制就更加重要了. 用反射和自定义注解来实 ...
- 缓存篇~第七回 Redis实现基于方法签名的数据集缓存(可控更新,分布式数据缓存)
返回目录 本篇文章可以说是第六回 Microsoft.Practices.EnterpriseLibrary.Caching实现基于方法签名的数据集缓存(可控更新,WEB端数据缓存)的续篇,事实上,有 ...
- Spring2.5那些事之基于AOP的方法级注解式日志配置
在日常开发中经常需要在代码中加入一些记录用户操作日志的log语句,比如谁在什么时间做了什么操作,等等. 把这些对于开发人员开说无关痛痒的代码写死在业务方法中实在不是一件很舒服的事情,于是AOP应运而生 ...
- java反射机制获取自定义注解值和方法
由于工作需求要应用到java反射机制,就做了一下功能demo想到这些就做了一下记录 这个demo目的是实现动态获取到定时器的方法好注解名称,废话不多说了直接上源码 1.首先需要自定义注解类 /** * ...
- 缓存篇~第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)
返回目录 上一讲主要是说如何将数据集存储到redis服务器里,而今天主要说的是缓存里的键名,我们习惯叫它key. redis或者其它缓存组件实现的存储机制里,它将很多方法对应的数据集存储在一个公共的空 ...
- Spring Security(17)——基于方法的权限控制
目录 1.1 intercept-methods定义方法权限控制 1.2 使用pointcut定义方法权限控制 1.3 使用注解定义方法权限控制 1.3.1 JSR-25 ...
随机推荐
- 我应该跟libuv说声对不起,我错怪了libuv(转)
一开始,我得向Libuv库和Libuv库开发者以及相关粉丝们道一个歉,对不起,我错怪你们了.深深感到自己的无知,是多么羞愧的事情!! 事情的经过是这样的. 原先按照公司要求,我在开发Win ...
- 点击劫持漏洞之理解 python打造一个挖掘点击劫持漏洞的脚本
前言: 放假了,上个星期刚刚学习完点击劫持漏洞.没来的及写笔记,今天放学总结了一下 并写了一个检测点击劫持的脚本.点击劫持脚本说一下哈.= =原本是打算把网站源码 中的js也爬出来将一些防御的代码匹配 ...
- java小知识点汇总
1.ConcurrentHashMap使用segment来分段和管理锁,segment继承自ReentrantLock,因此ConcurrentHashMap使用ReentrantLock来保证线程安 ...
- vue中get和post请求
import axios from 'axios'; import router from '@/router'; import { setSessionStorage, getSes ...
- FFPLAY的原理(一)
概要 电影文件有很多基本的组成部分.首先,文件本身被称为容器Container,容器的类型决定了信息被存放在文件中的位置.AVI和Quicktime就 是容器的例子.接着,你有一组流,例如,你经常有的 ...
- MySql 动态语句
MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) ...
- self-sizing cell的一个问题
如何TableViewCell里面再加上CollectionView这类的ScrollView玩意,那自动算高就失效了,还是得用 override func tableView(_ tableView ...
- Yii2数据接口
写接口之前先确认那你已经安装了Yii2的basic版或者advanced版,如果还没有,赶快去看这篇文章:composer安装Yii2. 现在默认你已经安装了basic版或者advanced版了,并且 ...
- SOFA 源码分析 — 连接管理器
前言 RPC 框架需要维护客户端和服务端的连接,通常是一个客户端对应多个服务端,而客户端看到的是接口,并不是服务端的地址,服务端地址对于客户端来讲是透明的. 那么,如何实现这样一个 RPC 框架的网络 ...
- STL-Vector源码剖析
G++ ,cygnus\cygwin-b20\include\g++\stl_vector.h 完整列表 /* * * Copyright (c) 1994 * Hewlett-Packard Com ...