1.自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface RedisCache {
//自定义key值(本文中未使用)
String prefix() default "";
//设置缓存时间
int expire() default 1;
//缓存时间类型
TimeUnit TIME_UNIT() default TimeUnit.HOURS;
//缓存反序列化获取的对象
Class clazz() default Object.class;
//序列化后的对象是否是jsonarry 比如 List<Object>
boolean isArray() default false;
}
2.切面
@Component
@Aspect
@Slf4j
public class RedisCacheAspect {
@Resource
private RedisTemplate redisTemplate;
/**
* 分隔符 生成key 格式为 类全类名|方法名|参数所属类全类名
**/
private static final String DELIMITER = "-";
/**
* Service层切点
*/
@Pointcut("@annotation(com.clc.info.annotation.RedisCache)")
public void redisCacheAspect() {
}
@Around(value = "redisCacheAspect()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
//redis序列化,防止存入redis key有乱码
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// 得到类名、方法名和参数
String clazzName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
log.info("参数-->{}", args);
// 根据类名、方法名和参数生成Key
String key = getKey(clazzName, methodName, args);
if (log.isInfoEnabled()) {
log.info("生成key: " + key);
}
// 得到被代理的方法
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
//redis 前缀
String prefix = method.getAnnotation(RedisCache.class).prefix();
int expire = method.getAnnotation(RedisCache.class).expire();
TimeUnit timeUnit = method.getAnnotation(RedisCache.class).TIME_UNIT();
Class objectType = method.getAnnotation(RedisCache.class).clazz();
boolean isArray = method.getAnnotation(RedisCache.class).isArray();
// 检查Redis中是否有缓存
String value = (String) redisTemplate.opsForValue().get(key);
// result是方法的最终返回结果
Object result = null;
try {
if (null == value) {
log.info("缓存未命中");
// 调用数据库查询方法
result = joinPoint.proceed(args);
// 结果放入缓存
redisTemplate.opsForValue().set(key, JSON.toJSONString(result), expire, timeUnit);
} else {
log.info("===========缓存命中===========");
/**
* 可以直接针对mapper进行缓存,如果mapper查询返回的List<DemoObjec> 需要isArray 为true 否则转换异常
*/
if (isArray) {
return JSON.parseArray(value, objectType);
} else {
return JSON.parseObject(value, objectType);
}
}
} catch (Throwable e) {
log.error("程序异常", e.getMessage());
throw e;
}
return result;
}
/**
* * 根据类名、方法名和参数生成Key
* * @param clazzName
* * @param methodName
* * @param args
* * @return key格式:全类名|方法名|参数类型
*/
private String getKey(String clazzName, String methodName, Object[] args) {
StringBuilder key = new StringBuilder(clazzName);
key.append(DELIMITER);
key.append(methodName);
key.append(DELIMITER);
key.append(Arrays.stream(args).map(x -> x.toString()).collect(Collectors.joining(DELIMITER)));
return key.toString();
}
}
3.Service使用
@RedisCache(expire = 1, clazz = FareBasic.class, isArray = true)
public List<FareBasic> getAll() {
return fareBasicRepository.findAll();
}