版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Yubu_/article/details/75099098
适合使用缓存的数据:
1 很少更新的数据
2 经常被用到的数据
3 数据量不大的数据
缓存控制
声明3个注解,对类或者方法是否支持缓存进行控制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCacheable {
int expire() default 600;//缓存过期时间,单位秒,默认60
}
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyUseCache {
}
@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyClearCache {
}
MyCacheable注解标注在类上,控制这个类的方法时候可以使用MyUseCache和MyClearCache注解
MyUseCache注解标注在方法上,在执行方法之前,先从缓存尝试获取数据,如果获取了,直接返回数据,如果没有获取到,执行方法进行查询,并且把查询到的数据放入缓存
MyClearCache注解标注在方法上,清空缓存
使用原则
会更新数据的操作都清理缓存
对于有关联关系的表,当相关联的表进行了更新操作时,会出现缓存数据和数据库数据不一致,通过设置缓存过期时间来解决。缓存过期时间根据数据不一致可接受时间决定
由于需要支持过期时间,需要每条缓存使用一个独立的key,为了对一个表的缓存进行全部删除,需要保证同一个类的缓存的key的前缀一致
value是json格式的字符串数据,如果查询方法的返回值不符合json格式,则不能使用缓存
实现缓存的AOP代码
@Aspect
public class CacheAspect {
@Pointcut("@target(com.my.annotation.MyCacheable)")
private void cacheable() {
}
@Pointcut("@annotation(com.my.annotation.MyUseCache)")
private void useCache() {
}
@Pointcut("@annotation(com.my.annotation.MyClearCache)")
private void clearCache() {
}
@SuppressWarnings("all")
@Around("cacheable() && useCache()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
//目标类Class对象
Class targetClass = joinPoint.getTarget().getClass();
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String key = createKey(joinPoint);
String value = JedisUtils.get(key);//从缓存中取数据
//如果缓存数据不为空,则直接使用缓存数据
if (!CommonUtils.isEmpty(value)) {
//方法返回值类型
Class returnType = ReflectUtils.getActualReturnType(targetClass, method);
//方法返回值类型的泛型类型
Class[] parametricTypes = ReflectUtils.getActualParametricTypeOfReturnType(targetClass, method);
return JsonUtils.toBean(value, returnType, parametricTypes);
} else {
//如果执行到这里就说明缓存里面没有数据,则执行正常逻辑(从数据库中查询数据)
Object returnObject = joinPoint.proceed();
MyCacheable cacheable = (MyCacheable) targetClass.getAnnotation(MyCacheable.class);
//把数据存入缓存
JedisUtils.setex(key, cacheable.expire(), JsonUtils.toJson(returnObject));
return returnObject;
}
}
@After("cacheable() && clearCache()")
public void after(JoinPoint joinPoint) {
//清空和此key前缀匹配的所有缓存
JedisUtils.del(createKeyPatternForDelete(joinPoint));
}
//生成要删除的redis key的正则表达式
private String createKeyPatternForDelete(JoinPoint joinPoint) {
StringBuilder keyPattern = new StringBuilder();
keyPattern.append("cache_").append(joinPoint.getTarget().getClass().getName()).append("_*");
return keyPattern.toString();
}
private String createKey(JoinPoint joinPoint) {
StringBuilder key = new StringBuilder();//redis缓存key的前缀
key.append("cache_").append(joinPoint.getTarget().getClass().getName()).append("_");
String signature = joinPoint.getSignature().toString();
signature = signature.substring(signature.lastIndexOf('.') + 1);
key.append(signature).append("_");
Object[] args = joinPoint.getArgs();
if (args != null && args.length > 0) {
String argsStr = JsonUtils.toJson(args);
//把:替换为_,避免生成命名空间
argsStr = argsStr.replaceAll(":", "_");
key.append(argsStr);
}
return key.toString();
}
}