最近测试跟我们说我们接口很慢,看了看是数据报表的接口慢,当时设计没有做缓存,每次都是实时查询数据库,也不想去优化sql。
就想着给接口加个缓存,后来看了接口很多,想了想能不能写个通用组件。毕竟很多接口其实也需要缓存。比如业务系统调用用户系统的用户详情,一般就显示一些名称和id,不需要那么的实时展示,也可以在远程调用上加个缓存。
AOP+注解+redis 方式实现,比较简单
注解,可以注解某个方法或者整个类的都需要缓存
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiCache {
}
切面实现
这个实现是一种最简单的实现,可以在后面有需求了在增加
扩展点一:getArgsIdentifyCode方法
获取区分码方法我直接使用ObjectMapper将所有参数转为一个string,然后取hashcode值,这种方法比较粗暴简单,可能会重复
如果需要的话可以将参数获取出单独按照类型处理,可以根据业务来
扩展点二:缓存名称和时间
可以做成中间组件,然后每个系统都能用,在名称前面加上业务code,缓存时间也可以根据接口动态配置,具体的可以看看极客时间设计模式后面的接口限流那一篇,将限流的改成接口缓存,可以动态配置接口的缓存时间
@Aspect
@Component
public class CacheAop {
private final RedisTemplate<String,Object> redisTemplate;
private final ObjectMapper objectMapper;
public CacheAop(RedisTemplate<String, Object> redisTemplate, ObjectMapper objectMapper) {
this.redisTemplate = redisTemplate;
this.objectMapper = objectMapper;
}
@Pointcut("(@annotation(com.annotations.ApiCache))" +
"|| (@within(com.annotations.ApiCache))")
private void annotationPointCut() {
}
@Around("annotationPointCut()")
public Object around(ProceedingJoinPoint point) {
//获取类名
String className = point.getTarget().getClass().getName();
//获取方法
String methodName = point.getSignature().getName();
//获取参数
Object[] args = point.getArgs();
Integer identifyCode = null;
//获取参数唯一编码
identifyCode = getArgsIdentifyCode(args, identifyCode);
String redisKey = className + ":" + methodName + ":" + identifyCode;
Object cacheResult = redisTemplate.opsForValue().get(redisKey);
if (ObjectUtils.isEmpty(cacheResult) || identifyCode == null) {
Object result = null;
try {
result = point.proceed();
} catch (Throwable e) {
throw new RuntimeException(e);
}
redisTemplate.opsForValue().set(redisKey, result, Duration.ofSeconds(30));
return result;
} else {
return cacheResult;
}
}
private Integer getArgsIdentifyCode(Object[] args, Integer hashCode) {
try {
hashCode = objectMapper.writeValueAsString(args).hashCode();
} catch (JsonProcessingException ignore) {
}
return hashCode;
}
}
这个是我一个比较简单的实现,具体的怎么样还得放到公司测试环境跑跑看,大家有什么好的建议可以交流一下