项目中有使用到缓存,每次需要将缓存代码和业务代码杂糅在一起,以及分散各处的key,严重影响代码的可读性。以下是使用AOP对其简单尝试。直接上代码:

1、定义缓存注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
long timeOut() default 0; TimeUnit timeUnit() default TimeUnit.HOURS;
}

2、定义参数唯一键注解,使用此注解标记此输入参数参与构成唯一键:

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheUniqueKey {
}

3、CacheAspect

@Component
@Slf4j
@Aspect
@Data
public class CacheAspect {
private final CacheCenter<String> cacheCenter;
   // 缓存开关配置
@Value("${service.cache}")
private boolean cacheEnable = false; @Around(value = "@annotation(com.yingying.survey.component.cache.Cache)&&@annotation(cache)")
public Object around(ProceedingJoinPoint joinPoint, Cache cache) throws Throwable {
if (!cacheEnable) {
return joinPoint.proceed();
} long timeOut = cache.timeOut();
TimeUnit timeUnit = cache.timeUnit();
if (timeOut == 0) {
return joinPoint.proceed();
} Class<?> clazz = joinPoint.getTarget().getClass();
String clazzSimpleName = clazz.getSimpleName();
String methodName = joinPoint.getSignature().getName(); Signature signature = joinPoint.getSignature();
Class declaringType = ((MethodSignature) signature).getReturnType(); String uniqueParam = methodParamsResolve(joinPoint);
String cacheKey = clazzSimpleName + ":" + methodName + ":" + uniqueParam;
if (cacheCenter.isExistCache(cacheKey)) {
String loadCache = cacheCenter.loadCache(cacheKey);
log.info("data from cache:{}", loadCache);
if (declaringType.isArray()) {
return JSONArray.parseArray(loadCache, declaringType);
} else {
return JSON.parse(loadCache, declaringType);
}
} Object proceedResult = joinPoint.proceed();
// 为了从缓存中取值时不出现空指针的情况,现不对返回值为空的结果缓存。
if (proceedResult != null) {
String cacheData = JSON.json(proceedResult);
CacheUnit cacheUnit = new CacheUnit().setTimeUnit(timeUnit).setCacheOutTime(timeOut).setCacheKey(cacheKey);
cacheCenter.insertCache(cacheUnit, cacheData);
} return proceedResult;
} private String methodParamsResolve(ProceedingJoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
Method method = ((MethodSignature) signature).getMethod();
Annotation[][] parameterAnnotations = method.getParameterAnnotations(); String uniqueParam = "";
int idx = 0;
for (Annotation[] annotations : parameterAnnotations) {
for (Annotation annotation : annotations) {
if (annotation instanceof CacheUniqueKey) {
Object[] args = joinPoint.getArgs();
uniqueParam = (String) args[idx];
return uniqueParam;
}
}
idx++;
}
return uniqueParam;
}
}

4、缓存配置单元:

@Data
@Accessors(chain = true)
public class CacheUnit {
@NotBlank
@NotNull
private String cacheKey; private long cacheOutTime = 0; @NotNull
private TimeUnit timeUnit;
}

5、缓存中心实现接口:

public interface CacheCenter<T> {
boolean isExistCache(@NotNull @NotBlank String cacheKey); T loadCache(@NotNull @NotBlank String cacheKey); boolean insertCache(@NotNull CacheUnit cacheUnit, @NotNull T cacheData);
}

6、基于Redis的缓存中心实现:

@Service("cacheCenter")
@Data
public class RedisCacheCenter implements CacheCenter<String> {
private final RedisService redisService; @Override
public boolean isExistCache(@NotNull @NotBlank String cacheKey) {
return redisService.exists(cacheKey);
} @Override
public String loadCache(@NotNull @NotBlank String cacheKey) {
return redisService.get(cacheKey);
} @Override
public boolean insertCache(@NotNull CacheUnit cacheUnit, @NotNull String cacheData) {
long cacheOutTime = TimeUnit.SECONDS.convert(cacheUnit.getCacheOutTime(), cacheUnit.getTimeUnit());
redisService.set(cacheUnit.getCacheKey().getBytes(), cacheData.getBytes(), cacheOutTime);
return true;
}
}

7、应用案例:

基于Redis的Service缓存实现的更多相关文章

  1. 基于redis的分布式缓存disgear开源到github上了

    disgear是笔者参考solrcloud架构基于redis实现的分布式的缓存,支持数据切分到多台机器上,支持HA,支持读写分离和主节点失效自动选举,目前把它开放到github上,开放给大家 gith ...

  2. Govern Service 基于 Redis 的服务治理平台

    Govern Service 基于 Redis 的服务治理平台(服务注册/发现 & 配置中心) Govern Service 是一个轻量级.低成本的服务注册.服务发现. 配置服务 SDK,通过 ...

  3. 基于Spring接口,集成Caffeine+Redis两级缓存

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 在上一篇文章Redis+Caffeine两级缓存,让访问速度纵享丝滑中,我们介绍了3种整合Caffeine和Redis作为两级缓存使用的方法,虽 ...

  4. 基于redis分布式缓存实现(新浪微博案例)

    第一:Redis 是什么? Redis是基于内存.可持久化的日志型.Key-Value数据库 高性能存储系统,并提供多种语言的API. 第二:出现背景 数据结构(Data Structure)需求越来 ...

  5. .NET基于Redis缓存实现单点登录SSO的解决方案[转]

    一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...

  6. .NET基于Redis缓存实现单点登录SSO的解决方案

    一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单点登录,现在就NET基于Redis缓存实现单点登录做一个简单的分享. 单点登录(Single Sign On),简称 ...

  7. 基于redis分布式缓存实现

    Redis的复制功能是完全建立在之前我们讨论过的基 于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redis的复制功能,就一定会有内存快照发生,那么首先要注意你 的 ...

  8. 基于Redis缓存的Session共享(附源码)

    基于Redis缓存的Session共享(附源码) 在上一篇文章中我们研究了Redis的安装及一些基本的缓存操作,今天我们就利用Redis缓存实现一个Session共享,基于.NET平台的Seesion ...

  9. redis结合自定义注解实现基于方法的注解缓存,及托底缓存的实现

    本次分享如何使用redis结合自定义注解实现基于方法的注解缓存,及托底缓存的实现思路    现在的互联网公司大多数都是以Redis作为缓存,使用缓存的优点就不赘述了,写这篇文章的目的就是想帮助同学们如 ...

随机推荐

  1. [安洵杯 2019]easy_serialize_php

    0x00 知识点 PHP反序列化的对象逃逸 任何具有一定结构的数据,只要经过了某些处理而把自身结构改变,则可能会产生漏洞. 参考链接: https://blog.csdn.net/a3320315/a ...

  2. sendmail 的安装、配置与发送邮件的具体实现

    Ubuntu 中sendmail 的安装.配置与发送邮件的具体实现 centos安装sendmail与使用详解 CentOS下搭建Sendmail邮件服务器 使用外部SMTP发送邮件  使用mailx ...

  3. DOM,windows 对象

    DOM:文档对象模型 --树模型文档:标签文档,对象:文档中每个元素对象,模型:抽象化的东西 windows 对象:浏览器窗口信息document对象:浏览器显示的页面文件 一:window: win ...

  4. lvm 逻辑卷分区删除恢复

    原因:执行 lvremove /dev/system/lv_trans 删除逻辑分区 恢复: 1.进入到lvm查看元数据 cd /etc/lvm/archive 2.恢复元vg卷组 vgcfgrest ...

  5. HTML5 SVG应用(1)——loading效果

    先看一下效果: 链接 代码: <svg version="1.1" id="loader-1" xmlns="http://www.w3.org ...

  6. ES系列之Promise async 和 await

    概述 promise是异步编程的一种解决方案,比传统的解决方案—回调函数和事件—更合理更强大. 所谓的promise就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作的结果). Pro ...

  7. 翻译——3_Gaussian Process Regression

    使用不同的机器学习方法进行预测 续上篇2_Linear Regression and Support Vector Regression 高斯过程回归 %matplotlib inline impor ...

  8. i春秋-web-爆破-1

    题目内容:flag就在某六位变量中. 题目 include "flag.php"; $a = @$_REQUEST['hello']; if(!preg_match('/^\w*$ ...

  9. (2)关于opencv解压

    关于opencv解压,一定不能解压到你的C盘的 ProgramFile(x86)中,不然,你肯定不会成功,你要放在C盘的其他文件夹,或者是别的盘中 就是因为这一个错误,我弄了一天,哎哎,时间宝贵啊

  10. Java static的用法以及原理(06)

    静态:static 用法:是一个修饰符,用于修饰成员(成员变量,成员函数), 当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调:类名.静态成员 类名.静态成员 存在:方 ...