栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

自定义注解缓存feign结果

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

自定义注解缓存feign结果

一、背景

在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
@Slf4j
public 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);
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/732432.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号