
声明注解 模仿@Transactianal
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface GmallCache {
/**
* 缓存key的前缀
*
* @return
*/
String prefix() default "cache";
/**
* 锁的后缀
*
* @return
*/
String suffix() default "cache";
}
添加切面类 纵向重复代码 横向提取出来 以分布式缓存+分布式锁代码为例
@Component
@Aspect
public class GmallCacheAspect {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
@SneakyThrows
@Around("@annotation(com.atguigu.gmall.common.cache.GmallCache)")//切GmallCache注解
public Object cacheAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
//声明一个对象
Object object = new Object();
try {
// 在环绕通知中处理业务逻辑 {实现分布式锁}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取到注解,注解使用在方法上!
GmallCache gmallCacheAnnotation = signature.getMethod().getAnnotation(GmallCache.class);
//获取key前缀 后缀
String prefix = gmallCacheAnnotation.prefix();
String suffix = gmallCacheAnnotation.suffix();
//获取参数
Object[] args = joinPoint.getArgs();
//拼key
String key = prefix + Arrays.asList(args) + suffix;
//锁key
String lockkey = prefix + Arrays.asList(args) + RedisConst.SKULOCK_SUFFIX;
//判断缓存中是否存在该数据
// 下面类似 Object o = redisTemplate.opsForValue().get(key);
object = cacheHit(key, signature);
//判断是否返回数据
if (null == object) {
//获取锁
RLock lock = redissonClient.getLock(lockkey);
boolean flag = lock.tryLock(RedisConst.SKULOCK_EXPIRE_PX1, RedisConst.SKULOCK_EXPIRE_PX2, TimeUnit.SECONDS);
try {
if (flag) {
//查数据库 执行方法体
object = joinPoint.proceed(joinPoint.getArgs());
if (null == object) {
//数据库为空
object = new Object();
//数据库不为空 放入缓存
Class returnType = signature.getReturnType();
object = returnType.newInstance();
redisTemplate.opsForValue().set(key, JSON.toJSONString(object), RedisConst.SKUKEY_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
return object;
}
redisTemplate.opsForValue().set(key, JSON.toJSONString(object), RedisConst.SKUKEY_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
return object;
} else {
Thread.sleep(1000);
this.cacheAroundAdvice(joinPoint);
}
} finally {
lock.unlock();
}
} else {
return object;
}
} catch (Exception e) {
e.printStackTrace();
}
//兜底方法
return joinPoint.proceed(joinPoint.getArgs());
}
/**
* 表示从缓存中获取数据
*
* @param key 缓存的key
* @param signature 获取方法的返回值类型
* @return
*/
private Object cacheHit(String key, MethodSignature signature) {
//透过key来获取缓存数据
String strJson = (String) redisTemplate.opsForValue().get(key);
// 表示从缓存中获取到了数据
if (!StringUtils.isEmpty(strJson)) {
// 字符串存储的数据是什么? 就是方法的返回值类型
Class returnType = signature.getReturnType();
//将字符串变为当前的返回值类型
return JSON.parseObject(strJson,returnType);
}
return null;
}
}
再切点上加注解 并指定前后缀
@GmallCache(prefix = "skuValueIdsMap:", suffix = RedisConst.SKUKEY_SUFFIX)
@Override
public List<Map> getSkuValueIdsMap(Long spuId) {
return skuSaleAttrValueMapper.selectSkuValueIdsMap(spuId);
}
@GmallCache(prefix = "spuSaleAttrListCheckBySku:", suffix = RedisConst.SKUKEY_SUFFIX)
@Override
public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
return spuSaleAttrMapper.selectSpuSaleAttrListCheckBySku(skuId, spuId);
}