优雅的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();
    }
    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中,你可以使用`@Cacheable`注解来启用缓存功能,并且可以与Redis集成来实现缓存。 `@Cacheable`注解可以应用在方法上,用于指示Spring在调用此方法之前,首先从缓存中查找对应的数据。如果缓存中有数据,则直接返回缓存中的数据,不再执行方法体内的代码。如果缓存中没有数据,则会执行方法体内的代码,并将返回值存储到缓存中。 要使用`@Cacheable`注解,你需要在启动类上添加`@EnableCaching`注解来启用缓存功能。此外,还需要配置Redis作为缓存的存储介质。 首先,引入依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 接下来,在`application.properties`或`application.yml`中配置Redis连接信息: ```yaml spring.redis.host=your_redis_host spring.redis.port=your_redis_port ``` 然后,在需要使用缓存的方法上添加`@Cacheable`注解,指定缓存的名称: ```java @Cacheable("myCache") public String getData(String key) { // 从数据库或其他数据源获取数据的逻辑 } ``` 以上示例中,方法`getData()`会先从名为`myCache`的缓存中查找数据,如果找到则直接返回缓存中的数据;如果没有找到,则执行方法体内的代码,并将返回值缓存起来。 注意:为了使`@Cacheable`注解生效,需要在启动类上添加`@EnableCaching`注解。 这样,你就可以在Spring Boot中使用Redis缓存注解来提高应用的性能了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值