前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot中使用注解读取redis缓存

SpringBoot中使用注解读取redis缓存

作者头像
半月无霜
发布2023-03-03 15:07:45
3830
发布2023-03-03 15:07:45
举报
文章被收录于专栏:半月无霜半月无霜

SpringBoot中使用注解读取redis缓存

一、介绍

我们使用redis的时候,一般都是以下这个步骤

  1. 查询指定的redis缓存
  2. 如果有直接返回,(异步执行查询,更新redis缓存)
  3. 如果没有则执行查询,(同时设置redis缓存)

此外,如果是增删改操作,将触发一次设置redis缓存的操作。

上面的一些步骤高度重复,我决定造个轮子,基于注解、切面和反射来完成此项功能。

二、相关代码

1)依赖

处于SpringBoot中,redisaop等相关依赖不要忘记

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2)代码

首先,我们先编写一个注解

代码语言:javascript
复制
package com.banmoon.test.annotations;

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 RedisCache {

    String value() default "hash";

    RedisCacheKeyModel keyModel() default RedisCacheKeyModel.METHOD_HASH;

    boolean write() default false;

    /**
     * 生成key的模式策略
     */
    enum RedisCacheKeyModel {

        /**
         * 自定义的key
         */
        CUSTOM(),

        /**
         * 方法名_hash值
         */
        METHOD_HASH();

    }

}

其次,我们编写切面了,针对上面注解的方法

简单的来说,就是获取注解标注的方法,通过注解上的参数,来确定key

有了key,先查询一遍redis,如果有值就直接返回;异步调用方法,并更新redis缓存;

代码语言:javascript
复制
package com.banmoon.test.aspect;

import com.banmoon.test.annotations.RedisCache;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Aspect
@Component
public class RedisCacheAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(com.banmoon.test.annotations.RedisCache)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String key = "";
        try {
            String methodName = joinPoint.getSignature().getName();
            Class<?> classTarget = joinPoint.getTarget().getClass();
            Class<?>[] par = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
            Method objMethod = classTarget.getMethod(methodName, par);

            RedisCache cache = objMethod.getAnnotation(RedisCache.class);
            if (RedisCache.RedisCacheKeyModel.CUSTOM == cache.keyModel()) {
                key = cache.value();
            } else {
                String canonicalName = String.format("%s.%s", classTarget.getCanonicalName(), methodName);
                key = String.format("%s_%s", methodName, canonicalName.hashCode());
            }

            if (cache.write()) {
                Object res = joinPoint.proceed();
                redisTemplate.opsForValue().set(key, res);
                return res;
            } else {
                Object res = redisTemplate.opsForValue().get(key);
                if (Objects.isNull(res)) {
                    res = joinPoint.proceed();
                    redisTemplate.opsForValue().set(key, res);
                } else {
                    String finalKey = key;
                    CompletableFuture.runAsync(() -> {
                        try {
                            Object res1 = joinPoint.proceed();
                            redisTemplate.opsForValue().set(finalKey, res1);
                        } catch (Throwable throwable) {
                        }
                    });
                }
                return res;
            }
        } catch (Exception e) {
            Object res = joinPoint.proceed();
            redisTemplate.opsForValue().set(key, res);
            return res;
        }
    }

}

3)测试使用

写一段测试方法,进行使用

TestController.java

代码语言:javascript
复制
package com.banmoon.test.controller;

import com.banmoon.test.dto.ResultData;
import com.banmoon.test.dto.UserDTO;
import com.banmoon.test.service.impl.TestServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private TestServiceImpl testServiceImpl;

    @GetMapping("/redisCache")
    public ResultData redisCache() {
        List<UserDTO> userList = testServiceImpl.getUserList();
        return ResultData.success(userList);
    }

}

TestServiceImpl.java

代码语言:javascript
复制
package com.banmoon.test.service.impl;

import com.banmoon.test.annotations.RedisCache;
import com.banmoon.test.dto.UserDTO;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class TestServiceImpl {

    @RedisCache("userList")
    public List<UserDTO> getUserList() {
        List<UserDTO> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            UserDTO dto = new UserDTO();
            dto.setName("半月无霜" + i);
            dto.setSex("男");
            dto.setAge(18+i);
            dto.setStatus(i%2);
            list.add(dto);
        }
        return list;
    }

}

请求url,http://localhost:8080/test/redisCache,可以正常返回,同时查看`redis`有无缓存

请求结果

redis缓存

https://banmoon-pic.oss-cn-guangzhou.aliyuncs.com/images/20220901154509.png https://banmoon-pic.oss-cn-guangzhou.aliyuncs.com/images/20220901154417.png

三、最后

注解、aop和反射配在一起可以做很多事!

许多轮子不就这样出来了么。

我是半月,祝你幸福!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SpringBoot中使用注解读取redis缓存
    • 一、介绍
      • 二、相关代码
        • 1)依赖
        • 2)代码
        • 3)测试使用
      • 三、最后
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档