使用AOP以及注解实现缓存组件
1. 为什么使用AOP和注解实现缓存?
项目是一个报表系统,使用druid.io查询hue,每次查询巨大,可以达到每次30多M,而且后台也有很多运算,每次查询对服务器对压力很大,经常出现young gc,因此计划加入缓存提高查询效率,同时减少服务端的压力。
2. 为什么这么设计?
报表系统的一个基本逻辑:根据查询参数查询数据库,由于是离线的库,每天刷一遍数据,所以每次请求之间的区别仅仅是传递的参数,所以可以将缓存的位置直接放在controller层,根据传递的参数来缓存数据,这样使用注解来实现就比较好了。
3. 注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Cache {
int expire() default 60 * 60 * 12;
String type() default "Object";
Class returnClass() default Object.class;
Class param() default Object.class;
}
其中expire是缓存的保存时间,type是返回的类型是Object还是List形式的对象,returnClass是返回的对象类型,param是参数的类型
4. 设计切面类
/**
* @author 张驰
* @since 26 九月 2018
*/
@Aspect
@Component
public class CacheInterceptor {
private static final String OBJECT = "Object";
private static final String LIST = "List";
private static final String PRE_KEY = "md_cache";
@Autowired
private JedisClient jedisClient;
@SuppressWarnings("unchecked")
@Around("@annotation(com.wormpex.data.warehouse.biz.utils.cache.Cache)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
if (joinPoint == null) {
return null;
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Cache myAnnotation = method.getAnnotation(Cache.class);
String type = myAnnotation.type();
Class returnClass = myAnnotation.returnClass();
String key = "";
try {
key = getKey(joinPoint, method);
//如果没有命中到缓存值。应该调用目标函数,通过目标函数计算实际值。
String result = jedisClient.get(key);
if (StringUtils.isNotBlank(result)) {
switch (type) {
case OBJECT:
if (returnClass.equals(JsonResult.class)) {
JsonResult jsonResult = JsonUtil.of(result, JsonResult.class);
if (!jsonResult.isSuccess()) {
jedisClient.del(key);
return joinPoint.proceed();
}
}
return JsonUtil.of(result, returnClass);
case LIST:
return JsonUtil.ofList(result, returnClass);
default:
jedisClient.del(key);
return joinPoint.proceed();
}
}
}
catch (Throwable t) {
jedisClient.del(key);
return joinPoint.proceed();
}
Object o = joinPoint.proceed();
jedisClient.set(key, JsonUtil.toJson(o));
jedisClient.expire(key, myAnnotation.expire());
return o;
}
/**
* 根据参数生成cachekey
* @param joinPoint
* @param method
* @return
*/
@SuppressWarnings("unchecked")
private String getKey(ProceedingJoinPoint joinPoint, Method method) {
Class paramClass = method.getAnnotation(Cache.class).param();
String methodName = method.getDeclaringClass().getPackage().toString() + method.getName() + paramClass.getName();
return PRE_KEY + methodName + MD5Util.encode(String.valueOf(JsonUtil.toJson(get(paramClass, joinPoint.getArgs()[0]))));
}
private static <T> T get(Class<T> clz, Object o) {
if (clz.isInstance(o)) {
return clz.cast(o);
}
throw new IllegalArgumentException();
}
}
来源:https://www.cnblogs.com/zhangchiblog/p/9718952.html