使用Spring的@Cacheable实现Reids缓存时,会遇到过期时间不能直接在注解中赋值的问题,在项目中自己动手实现一个基于注解的RedisCache处理,可以在注解中直接指定Key(键)和Expired(过期时间)。然后AOP拦截,解析注解并做相应处理。
注解定义如下:
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCache {
/**
* 键
* @return
*/
String key() default "";
/**
* 过期时间
* @return
*/
long expired() default -1;
/**
* 是否为查询操作
* 如果为写入数据库的操作,该值需置为 false
* @return
*/
boolean read() default true;
}
AOP拦截类如下:
@Component
@Aspect
public class RedisCacheAspect {
private final static Logger logger = LoggerFactory.getLogger(RedisCacheAspect.class);
@Autowired
private RedisTemplate redisTemplate;
/**
* 定义切入点,使用了 @RedisCache 的方法
*/
@Pointcut("@annotation(RedisCache)")
public void redisServicePoint(){
}
/**
* 环绕通知,方法拦截器
*/
@Around("redisServicePoint()")
public Object WriteReadFromRedis(ProceedingJoinPoint point){
logger.info("<====== 进入 redisCache 环绕通知 ======>");
try {
// 获取RedisCache注解
RedisCache redisCache = ((MethodSignature)point.getSignature()).getMethod().getAnnotation(RedisCache.class);
if(redisCache != null && redisCache.read()){
// 查询操作
Object obj = redisTemplate.opsForValue().get(redisCache.key());
if(obj == null){
// Redis 中不存在,则从数据库中查找,并保存到 Redis
logger.info("<====== Redis 中不存在该记录,从数据库查找 ======>");
obj = point.proceed();
if(obj != null) {
if(redisCache.expired() > 0) {
redisTemplate.opsForValue().set(redisCache.key(), obj, redisCache.expired(), TimeUnit.SECONDS);
}else {
redisTemplate.opsForValue().set(redisCache.key(), obj);
}
}
}
return obj;
}
}catch (Throwable ex){
logger.error("<====== RedisCache 执行异常: {} ======>", ex);
}
return null;
}
}
在查询方法中使用注解:
@RedisCache(key = "test_user", expired = 30000)
public User findById(Long uid) {
return userMapper.selectByPrimaryKey(uid);
}
这样就实现了一个简单基于AOP的Redis缓存处理过程,该方法可以根据需要进行各种扩展。