优雅的Redis缓存注解

Redis缓存注解

注解

@RedisCache 添加缓存

  1. 将注解添加到需要缓存的方法上,指定缓存的key
  2. 指定缓存保存的类
  3. 指定存活时间
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
    String key() default "";

    Class type();

    long expireTime() default 3600L;
}

@RedisRelease 缓存释放

  1. 指定要释放的缓存的类
  2. 指定要释放哪个方法的缓存
  3. 是否清空redis中所有缓存
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisRelease {

    Class[] type() default {};

    String[] method() default {};

    boolean releaseAll() default false;
}

添加了@RedisCache后执行方法后,会进入切面,判断是否命中缓存,如果命中缓存则返回缓存数据,没有命中,则会才回去查询数据库,再把数据缓存之后返回

添加了@RedisRelease执行方法后,会进入切面将缓存释放

切面类

@Aspect
@Component
@Slf4j
public class RedisCacheAspect {
    @Autowired
    private RedisTemplate redisTemplate;

    private String prefix = "cache:thx";

    @Around("@annotation(com.thx.redisaop.aop.RedisCache)")
    public Object customerRedisCache(final ProceedingJoinPoint jp) throws Throwable {
        Method method = getMethod(jp);
        //获取方法上添加的注解
        RedisCache redisCache = method.getAnnotation(RedisCache.class);
        StringBuffer key = new StringBuffer();
        // THX TODO 2023/11/9 15:28: 未来会解析参数并将参数拼到key中
        //key默认为 prefix:缓存类的全类名:执行方法名:注解中指定的key值
        key.append(prefix).append(":").append(redisCache.type().getName()).append(":").append(method.getName()).append(":").append(redisCache.key());
        //获取注解中的要缓存的类
        Class modelType = redisCache.type();
        String value = (String) redisTemplate.opsForValue().get(key.toString());
        Object resutl;
        //判断redis中是否存缓存
        if (value == null) {
            log.info("未命中缓存,重新缓存");
            //执行原方法获取数据
            resutl = jp.proceed(jp.getArgs());
            //将数据存入Redis作为缓存数据
            String jsonString = JSON.toJSONString(resutl);
            redisTemplate.opsForValue().set(key.toString(), jsonString,redisCache.expireTime(), TimeUnit.SECONDS);
        } else {
            //命中缓存
            log.info("命中缓存,返回缓存数据");
            //获取接口或方法的返回值类型
            Class returnType = ((MethodSignature) jp.getSignature()).getReturnType();
            resutl = deserialize(value, returnType, modelType);
            return resutl;
        }
        return resutl;
    }

    @Around("@annotation(com.thx.redisaop.aop.RedisRelease)")
    public Object customerRedisRelease(final ProceedingJoinPoint jp) throws Throwable {
        Method method = getMethod(jp);

        Class[] classes = method.getAnnotation(RedisRelease.class).type();
        String[] methods = method.getAnnotation(RedisRelease.class).method();

        //判断是否需要释放所有缓存
        if (method.getAnnotation(RedisRelease.class).releaseAll()) {
            Set keys = redisTemplate.keys(prefix + ":*");
            if (CollectionUtils.isNotEmpty(keys)) {
                redisTemplate.delete(keys);
            }
        } else if (classes.length > 0) {
            StringBuffer stringBuffer = new StringBuffer();
            for (int i = 0; i < classes.length; i++) {
                Class classItem = classes[i];
                String className = classItem.getName();
                if (methods.length == 0) {
                    stringBuffer.setLength(0);
                    stringBuffer.append(prefix).append(":").append(className).append(":").append("*");
                    //获取模糊匹配的Key
                    Set keys = redisTemplate.keys(stringBuffer.toString());
                    if (CollectionUtils.isNotEmpty(keys)) {
                        redisTemplate.delete(keys);
                    }
                    log.info("删除指定类中所有方法的缓存:{}", stringBuffer.toString());
                } else {
                    String classMethod = methods[i];
                    //如果指定了方法名则删除指定方法的缓存
                    if (StringUtils.isNotEmpty(classMethod)) {
                        List<String> methodNameList = Arrays.asList(classMethod.split(";"));
                        for (String methodName : methodNameList) {
                            stringBuffer.setLength(0);
                        stringBuffer.append(prefix).append(":").append(className).append(":").append(methodName).append(":").append("*");
                            Set keys = redisTemplate.keys(stringBuffer.toString());
                            if (CollectionUtils.isNotEmpty(keys)) {
                                redisTemplate.delete(keys);
                            }
                            log.info("删除指定类中指定方法的缓存:{}", stringBuffer.toString());
                        }
                    }
                }
            }
        }
        return jp.proceed(jp.getArgs());
    }

    /*
     * 获取方法对象
     * @author thx
     * @date 2023/11/9
     * @param jp
     * @return Method
     */
    public Method getMethod(ProceedingJoinPoint jp) {
        Class[] types = ((MethodSignature) jp.getSignature()).getParameterTypes();
        Method method = null;
        try {
            method = jp.getTarget().getClass().getMethod(jp.getSignature().getName(), types);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return method;
    }

    //通过获取的要缓存的类将数据进行反序列化
    public Object deserialize(String jsonStr, Class clazz, Class modelType) {
        //如果返回值是List对象
        if (clazz.isAssignableFrom(List.class)) {
            return JSON.parseArray(jsonStr, modelType);
        }
        return JSON.parseObject(jsonStr, Object.class, JSONReader.Feature.SupportAutoType);
    }

}

使用示例

@RequestMapping("/redis")
@RestController
@Slf4j
public class RedisController {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StudentService studentService;

    @PostMapping("/add")
    @RedisRelease(type = {Student.class}, method = {"test"} )
    public void add(@RequestBody Student student){
        studentService.save(student);
    }

    @GetMapping("/test")
    @RedisCache(key = "stu",type = Student.class,expireTime = 180L)
    public List<Student> test(){
        return studentService.list();
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值