AOP实现缓存业务
AOP作用
AOP的主要的功能,实现方法扩展,对原有的业务逻辑解耦
AOP配置
切面 = 切入点表达式 + 通知方法
切入点表达式
1.bean com.jt.user 按类匹配,单独的类
2.within(com.jt.*) 按类匹配,控制粒度较粗.
3.execution(返回值类型 包名.类名.方法名(参数列表))
execution(* com.jt.service..*.*(..))
4.annotation(自定义注解)
环绕通知
五大通知类型中,只有环绕通知可以控制目标方法是否执行. JoinPoint.proceed();
AOP缓存设计
设计说明
可以采用自定义注解的形式,控制缓存操作.
问题说明:
1. 用户的key如何标识? 1.自动获取 2.允许用户自己设定
2. 数据是否需要设定超时时间? 指定一个时间属性
自定义注解设计 CacheFind
@Target(ElementType.METHOD)//注解对谁有效
@Retention(RetentionPolicy.RUNTIME)//运行时有效
public @interface CacheFind {
String key() default "";//如果用户设定参数,则使用用户的,如果用户没有设定参数,就使用自动生成
int seconds() default 0;//默认值为0
}
编辑CacheAOP
/**
* 1.添加环绕通知,使用环绕通知必须添加返回值
* 2.拦截自定义注解
* 需求:动态获取自定义注解中的参数
* 工作原理说明:
* 定义注解的变量名称 cacheFind
* 通知参数接收名称 cacheFind
* 除了匹配名称之外,还需要匹配类型.
* 注意事项:
* 1.环绕通知使用时,必须添加ProceedingJoinPoint
* 2.并且其中的参数joinPoint,必须位于第一位.
* 缓存实现业务思路:
* 1.准备key 1:动态的生成key 2:用户指定的key,key是否有值.
* 2.查询缓存
* 2.1没有数据,执行数据库操作→执行目标方法
* 将目标方法的返回值转化为JSON串,保存到redis中.
* 2.2有数据,动态获取缓存数据之后利用工具API转化为真实的对象.
*/
@Component //将对象交给spring容器管理
@Aspect //自定义切面
public class CacheAOP {
@Autowired
private Jedis jedis;
@Around("@annotation(cacheFind)")
public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind) {
//调用方法,获取key
String key = getKey(joinPoint, cacheFind);
String value = jedis.get(key);
Object object = null;
try {
if (StringUtils.isEmpty(value)) {
//缓存中没有数据,查询数据库
object = joinPoint.proceed();
String json = ObjectMapperUtil.toJson(object);
//判断是否需要超时设定
if (cacheFind.seconds()>0) {
jedis.setex(key, cacheFind.seconds(), json);
} else {
//该数据永不超时
jedis.set(key, json);
}
} else {
//需要动态的获取返回值类型
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Class<?> targetClass = methodSignature.getReturnType();
object = ObjectMapperUtil.toObject(value, targetClass);
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return object;
}
//动态获取key
private String getKey(ProceedingJoinPoint joinPoint, CacheFind cacheFind) {
//1.检查用户是否传递key
String key = cacheFind.key();
if (StringUtils.isEmpty(key)) {
//包名.类名.方法名::第一个参数
String className = joinPoint.getSignature().getDeclaringTypeName();
String mothedName = joinPoint.getSignature().getName();
Object arg0 = joinPoint.getArgs()[0];
key = className + "." + mothedName + "::" + arg0;
}
return key;
}
}
商品分类、商品列表实现缓存
@Autowired
private ItemCatMapper itemCatMapper;
@Autowired
private Jedis jedis;
@Override
@CacheFind//查询的注解
public List<EasyUITree> findListByParentId(Long parentId) {
QueryWrapper<ItemCat>queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id",parentId);
List<ItemCat>itemCatList=itemCatMapper.selectList(queryWrapper);
List<EasyUITree>easyUITreeList = new ArrayList<>(itemCatList.size());
for (ItemCat itemCat: itemCatList) {
Long id = itemCat.getId();
String text = itemCat.getName();
String state = itemCat.getIsParent()?"closed":"open";
EasyUITree easyUITree = new EasyUITree(id,text,state);
easyUITreeList.add(easyUITree);
}
return easyUITreeList;
}
@Override
@CacheFind
public String findItemName(Long itemCatId) {
ItemCat itemCat = itemCatMapper.selectById(itemCatId);
return itemCat.getName();
}