SpringBoot中使用注解读取redis缓存
2023-06-13 09:15:28 时间
SpringBoot中使用注解读取redis缓存
一、介绍
我们使用redis
的时候,一般都是以下这个步骤
- 查询指定的
redis
缓存 - 如果有直接返回,(异步执行查询,更新
redis
缓存) - 如果没有则执行查询,(同时设置
redis
缓存)
此外,如果是增删改操作,将触发一次设置redis
缓存的操作。
上面的一些步骤高度重复,我决定造个轮子,基于注解、切面和反射来完成此项功能。
二、相关代码
1)依赖
处于SpringBoot
中,redis
、aop
等相关依赖不要忘记
<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)代码
首先,我们先编写一个注解
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缓存;
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
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
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
和反射配在一起可以做很多事!
许多轮子不就这样出来了么。
我是半月,祝你幸福!!!
相关文章
- Redis让性能提升精准掌控缓存(怎样用redis做缓存)
- Redis缓存助力网页性能提升(网页缓存之redis)
- 使用Redis进行集合缓存优化(用redis缓存集合)
- 实现MySQL数据库表映射到Redis缓存(数据库表映射到redis)
- 华为Redis集群探索分布式缓存的极致性能(华为redis集群实例)
- 重新开启前台清除Redis缓存(前台清除 redis)
- 快速搭建Redis容器,轻松实现数据缓存(创建redis容器)
- 实现低成本的Redis分布式缓存数据迁移(分布式缓存redis迁移)
- 如何快速清理Redis缓存(如何清redis缓存)
- 深入探索Redis的默认缓存清空机制(redis默认缓存清空)
- 策略最近最少使用策略优化Redis集群性能(redis集群使用lru)
- 从 Redis 队列开始实现实时处理场景(redis 队列案例)
- Redis卡死网络受不了的沉重一击(redis造成网络卡死)
- 红色之火Redis通讯模型大开眼界(redis通讯模型)
- Redis集群上安全使用JWT(redis集群jwt)
- 使用Redis简单设定键值(redis设置key的值)
- Redis技术快速入门视频详解(redis视频介绍)
- Redis优雅获取所有键值对(redis 获取所有的值)
- 红色钥匙揭示Redis缓存中的锁机制(redis缓存涉及的锁)
- Redis缓存释放更大性能(redis 缓存前缀)
- Redis加入路由,实现无止境的进步(redis添加路由)