欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

自定义注解缓存feign结果

时间:2023-07-04
一、背景

在springcloud微服务架构中,可能会经常通过 feign 组件调用其它的微服务,feign的底层其实是模拟一个http请求,通过访问接口的方式调用远程服务,要经历三次握手建立TCP连接,在项目中是一个比较“耗时”的操作。
如果经常请求一些很少变动的数据,或者在一定时间段内可容忍已过期的数据,那么则需要在调用feign之前能不能从缓存中获取,可以自定义注解,将feign返回的结果缓存到redis中一段时间。

二、自定义注解

项目中需要使用:redis,aspect

1 - 定义一个注解标记需要缓存的方法

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 redisTemplate = redisUtil.getRedisTemplate(); Set keys = redisTemplate.keys(FEIGN_CLIENT_CACHE_PREFIX + "*"); if (keys != null) { Long count = redisTemplate.delete(keys); log.info("feign cache has bean deleted, count = {}", count); } }}

3 - redis操作工具类

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 redisTemplate; public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } public RedisTemplate getRedisTemplate() { return redisTemplate; } public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } @SuppressWarnings("unchecked") public void del(String..、key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete(CollectionUtils.arrayToList(key)); } } } // ============================String============================= public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } public Map hmget(String key) { return redisTemplate.opsForHash().entries(key); } public boolean hmset(String key, Map map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); }}

三、使用

以上工作做完之后,使用起来就非常方便了,直接在需要缓存的方法上使用注解即可

@GetMapping("/api/v1/city/{identity}") @FeignCache(expiresIn = 2 * 60 * 60) Response getCity(@PathVariable(value = "identity") String identity);

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。