1.自定义注解属性名称
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RedisCacheable {
enum KeyMode {
DEFAULT, //只有加了@CacheKey的参数,才加入key后缀中
BASIC, //只有基本类型参数,才加入key后缀中,如:String,Integer,Long,Short,Boolean
ALL, //所有参数都加入key后缀
USER, //所有参数都加入key后缀,并且加入当前访问用户ID
BEAN, //bean的属性加入KEY后缀
MAP //Map的属性加入KEY后缀
}
String key() default ""; //缓存key
KeyMode keyMode() default KeyMode.USER; //key的后缀模式
int expire() default 10; //缓存多少秒,默认10秒
2.自定义切面
@Aspect
@Component
public class RedisCacheableAspect {
Logger logger = LoggerFactory.getLogger(RedisCacheableAspect.class);
@Around("@annotation(cache)")
public Object cached(final ProceedingJoinPoint pjp, RedisCacheable cache) throws Throwable {
String key = null;
Object value = null;
try {
MethodSignature signature = (MethodSignature)pjp.getSignature();
Class returnType = signature.getReturnType();
key = getCacheKey(pjp, cache);
// 从缓存获取数据
value = RedisCacheService.get(key, returnType);
if (value != null) {
logger.info("**********RedisCacheableAspect返回Redis公共缓存数据:" + value);
return value;
}
} catch (Exception e) {
logger.error(e.getMessage());
}
// 跳过缓存,到后端查询数据
value = pjp.proceed();
if (value == null) {
return value;
}
try {
if (cache.expire() <= 0) {
// 如果没有设置过期时间,则无限期缓存
RedisCacheService.set(key, value);
} else {
// 否则设置缓存时间
RedisCacheService.set(key, value, cache.expire());
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return value;
}
/**
* 获取缓存的key值
*
* @param joinPoint
* @param cache
* @return
*/
private String getCacheKey(ProceedingJoinPoint joinPoint, RedisCacheable cache) {
// 切点的类完全限定名称
String className = joinPoint.getSignature().toString();
StringBuilder buf = new StringBuilder("CACH-ANNO-APP-");
buf.append(className);
String keyStr = cache.key();
if (cache.keyMode() == RedisCacheable.KeyMode.BEAN) {
if (keyStr.length() > 0) {
buf.append(".").append(keyStr);
}
}
Object[] args = joinPoint.getArgs();
if (cache.keyMode() == RedisCacheable.KeyMode.DEFAULT) {
Annotation[][] pas = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterAnnotations();
for (int i = 0; i < pas.length; i++) {
Object target = args[0];
Field field = ReflectionUtils.findField(target.getClass(), keyStr);
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, target);
buf.append("#").append(value);
}
} else if (cache.keyMode() == RedisCacheable.KeyMode.MAP) {
if (keyStr.length() > 0) {
Map target = (Map)args[0];
buf.append("#").append(target.get(keyStr));
}
} else if (cache.keyMode() == RedisCacheable.KeyMode.ALL) {
buf.append(Arrays.toString(joinPoint.getArgs()));
} else if (cache.keyMode() == RedisCacheable.KeyMode.USER) {
buf.append(Arrays.toString(joinPoint.getArgs()));
buf.append("#").append(CurrentUserUtil.getUsername());
}
return buf.toString();
}
}
3.方式使用自定义注解实现缓存
@RedisCacheable(keyMode = RedisCacheable.KeyMode.ALL, expire = 60 * 60 * 24)
public void testmethod() {
}
4.redis的后台监控
进入redis客户端,使用MONITOR命令可以监控redis的set和get过程。