在springcloud微服务架构中,可能会经常通过 feign 组件调用其它的微服务,feign的底层其实是模拟一个http请求,通过访问接口的方式调用远程服务,要经历三次握手建立TCP连接,在项目中是一个比较“耗时”的操作。
如果经常请求一些很少变动的数据,或者在一定时间段内可容忍已过期的数据,那么则需要在调用feign之前能不能从缓存中获取,可以自定义注解,将feign返回的结果缓存到redis中一段时间。
1 - 定义一个注解标记需要缓存的方法项目中需要使用:redis,aspect
package cn.wework.backend.aspect;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface FeignCache { long expiresIn() default -1;}
2 - 定义切面package cn.wework.backend.aspect;import cn.hutool.extra.spring.SpringUtil;import cn.wework.backend.common.constant.GlobalConstant;import cn.wework.backend.util.RedisUtil;import com.alibaba.fastjson.JSON;import lombok.extern.slf4j.Slf4j;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.reflect.MethodSignature;import org.springframework.beans.factory.InitializingBean;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.interceptor.SimpleKeyGenerator;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.stereotype.Component;import java.util.Arrays;import java.util.Set;@Aspect@Component@Slf4jpublic class FeignClientAspect implements InitializingBean { @Autowired private RedisUtil redisUtil; private static final String FEIGN_CLIENT_CACHE_PREFIX = "FEIGN-CLIENT-CACHE:"; @Around("@annotation(cn.wework.backend.aspect.FeignCache)") public Object cacheAround(ProceedingJoinPoint joinPoint) throws Throwable { String key = FEIGN_CLIENT_CACHE_PREFIX + joinPoint.getSignature().getDeclaringTypeName() + "#" + joinPoint.getSignature().getName() + "#" + SimpleKeyGenerator.generateKey(joinPoint.getArgs()); Object cache = redisUtil.get(key); if (cache != null) { return cache; } MethodSignature signature = (MethodSignature) joinPoint.getSignature(); FeignCache annotation = signature.getMethod().getAnnotation(FeignCache.class);// 这里可以对结果进行过滤,缓存正确的结果,视具体的业务逻辑来定 cache = joinPoint.proceed(joinPoint.getArgs()); redisUtil.set(key, cache, annotation.expiresIn()); return cache; } @Override public void afterPropertiesSet() { RedisTemplate
package cn.wework.backend.util;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.util.CollectionUtils;import java.util.List;import java.util.Map;import java.util.Set;import java.util.concurrent.TimeUnit;public class RedisUtil { private RedisTemplate
以上工作做完之后,使用起来就非常方便了,直接在需要缓存的方法上使用注解即可
@GetMapping("/api/v1/city/{identity}") @FeignCache(expiresIn = 2 * 60 * 60) Response