注解类
我们最常见的使用的是@Transactional,这个注解可以在代码出异常的时候进行事务回滚的操作,我们也可以写一个注解类搭配AOP切面帮助我们实现一些特定的业务需求,如日志的打印,记录用户的操作,搭配缓存解决一些寻常的查询业务等,下面我使用一个实例来整一个简单的注解搭配AOP切面实现的缓存查询方法
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheDemo {
String prefix() default "cache";
}
@Aspect
@Component
@Slf4j
public class CacheAspect{
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
@Around(value = "@annotation()")
public Object cacheAspectMethod(ProceedingJoinPoint proceedingJoinPoint){
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
Method method = signature.getMethod();
CacheDemo cache = method.getAnnotation(CacheDemo.class);
Class returnType = signature.getReturnType();
Object[] args = proceedingJoinPoint.getArgs();
String cacheKey = gmallCache.prefix() + Arrays.asList(args);
Object obj = redisTimplate.opsForValue().get(cacheKey);
if(obj == null){
String cacheLockKey = cache.prefix() + Arrays.asList(args) + ":inif";
RLock rLock = redissonClient.getLock(cacheLockKey);
try {
boolean tryLock = rLock.tryLock(1,6, TimeUnit.SECONDS);
if (tryLock){
try {
Object o1 = proceedingJoinPoint.proceed(args);
if (null != o1){
redisTemplate.opsForValue().set(cacheKey,
o1,RedisConst.SKUKEY_TIMEOUT + new Random().nextInt(300)
,TimeUnit.SECONDS);
}else {
o1 = returnType.getDeclaredConstructor().newInstance();
redisTemplate.opsForValue().set(cacheKey,
o1,5,TimeUnit.SECONDS);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}finally {
rLock.unlock();
}
}else {
try {
TimeUnit.SECONDS.sleep(2);
return redisTemplate.opsForValue().get(cacheKey);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}catch (Exception e){
e.printStackTrace();
}
}
log.info("返回了:cacheKey:{} :缓存中有数据.", JSONObject.toJSONString(obj));
return obj;
}
}
public class Demo{
@CacheDemo(prefix = "User:")
public User getBaseCategoryView(Long id) {
return UserMapper.selectById(id);
}
}