基于注解實現(xiàn),一個注解搞定緩存
Aop:面向切面編程,在不改變核心代碼的基礎上實現(xiàn)擴展,有以下應用場景
①事務
②日志
③controlleradvice+expetcationhandle實現(xiàn)全局異常
④redissson+aop實現(xiàn)分布式鎖
⑤認證授權
Aop的實現(xiàn)存在與bean的后置處理器beanpostprocessAfterinitlazing
一,實現(xiàn)步驟
1.定義注解
注解的定義仿照@translation進行定義
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface GmallCache {
//注解里面的自定義參數(shù)
String prefix() default "cache";
String suffix() default "info";
}
2.創(chuàng)建切面
參照官網(wǎng)文章來源:http://www.zghlxwxcb.cn/news/detail-805593.html
https://docs.spring.io/spring-framework/docs/5.3.9-SNAPSHOT/reference/html/core.html#aop文章來源地址http://www.zghlxwxcb.cn/news/detail-805593.html
@Aspect //定義一個切面
@Component //交給ioc管理
public class GmallAspect {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
/**
* 使用注解+aop實現(xiàn)緩存實現(xiàn)思路
* ①首先的定義一個注解,仿照@transactional注解去實現(xiàn),他就是在aop的基礎上實現(xiàn)的
* ②定義一個切面,交由ioc容器來管理
* ③去官網(wǎng)找到環(huán)繞通知的實例在此基礎上進行修改
* ④around注解里面掃描所有加了定義注解的內(nèi)容
* ⑤方法體里面首先獲取添加了注解的方法,然后獲取方法上的注解以及里面的參數(shù)
* ⑥一切準備就緒,準備redis里面的key,先從redis里面查詢,根據(jù)json數(shù)據(jù),判斷是否為空,如果為空直接返回空,如果不為空,則獲取運行時類型,根據(jù)反射拿到對象
*⑦redis里面有,直接返回
* ⑧redis里面沒有,定義lockKey,上鎖
* ⑨判斷是否拿到鎖,拿不到則等待一會兒,并自旋
* ⑩拿到鎖,則從數(shù)據(jù)庫查詢
* 查詢到:存往redis,返回,由于不確定對象的類型,此處存往reids使用json格式
* 查詢不到:預防緩存穿透①存空串(不建議)②使用反射創(chuàng)建空對象返回
* 十一:釋放鎖
*/
//定義一個環(huán)繞通知并且掃描,簡單的說就是對加了這個注解的所有方法增強
@Around("@annotation(com.atguigu.gmall.common.cache.GmallCache)")
public Object gmallCacheImpl(ProceedingJoinPoint joinPoint) throws Throwable {
//創(chuàng)建返回對象
Object object = new Object();
//獲取加了注解的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//獲取注解
GmallCache annotation = method.getAnnotation(GmallCache.class);
//獲取注解參數(shù)
String prefix = annotation.prefix();
String suffix = annotation.suffix();
//準備key
String key = prefix + Arrays.toString(joinPoint.getArgs()) + suffix;
//從緩存里面查詢
object = cacheNull(key, signature);
//判斷緩存是否存在
if (ObjectUtils.isEmpty(object)) {
//不存在,從數(shù)據(jù)庫查詢
//上鎖
String lockKey = prefix + Arrays.toString(joinPoint.getArgs());
//獲取鎖
RLock lock = redissonClient.getLock(lockKey);
boolean res = lock.tryLock(20, 10, TimeUnit.SECONDS);//此處數(shù)字要定義為常量
try {
if (res) {
//獲取到了鎖
//從數(shù)據(jù)庫查詢
object = joinPoint.proceed();
if (ObjectUtils.isEmpty(object)) {
//使用拿到返回值的運行時類型,使用反射創(chuàng)建對象
Object instance = signature.getReturnType().newInstance();
//數(shù)據(jù)庫查詢不到,預防緩存穿透
// Object obj = new Object();
//存儲到數(shù)據(jù)庫
redisTemplate.opsForValue().setIfAbsent(key, JSON.toJSONString(instance), 15, TimeUnit.SECONDS);
return instance;//返回skuinfo
} else {
//查詢到了
//存儲到數(shù)據(jù)庫
redisTemplate.opsForValue().set(key, JSON.toJSONString(object));
return object;
}
} else {
//沒有獲取到等待,自旋
Thread.sleep(300);
return gmallCacheImpl(joinPoint);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
} finally {
//解鎖
lock.unlock();
}
} else {
//存在
return object;
}
//保底從數(shù)據(jù)庫查詢
return joinPoint.proceed();
}
/**
* 從緩存查詢數(shù)據(jù)
*
* @param key
* @param signature
* @return
*/
private Object cacheNull(String key, MethodSignature signature) {
String str = (String) redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(str)) {
//獲取返回類型
Class returnType = signature.getReturnType();
//轉換
Object object = JSON.parseObject(str, returnType);
return object;
}
return null;
}
}
到了這里,關于redisson+aop實現(xiàn)分布式鎖的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!