基于接口缓存

110 阅读2分钟

最近测试跟我们说我们接口很慢,看了看是数据报表的接口慢,当时设计没有做缓存,每次都是实时查询数据库,也不想去优化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;  
}  
}

这个是我一个比较简单的实现,具体的怎么样还得放到公司测试环境跑跑看,大家有什么好的建议可以交流一下