joozh 发表于 2015-7-20 10:18:21

使用AOP 实现Redis缓存注解,支持SPEL

  公司项目对Redis使用比较多,因为之前没有做AOP,所以缓存逻辑和业务逻辑交织在一起,维护比较艰难
所以最近实现了针对于Redis的@Cacheable,把缓存的对象依照类别分别存放到redis的Hash中,对于key也实现了SPEL支持。
  1.applicationContext.xml,配置JedisPool














  2.Redis的封装类,使用FastJSON进行JSON和Object的转化,这里只用到了hset,hget,hdel,其他省略了



@Component
public class RedisCacheBean {
@Resource
JedisPool jedisPool;
/**
* 把对象放入Hash中
*/
public void hset(String key,String field,Object o){
Jedis jedis =jedisPool.getResource();
jedis.hset(key,field, JsonUtil.toJSONString(o));
jedisPool.returnResource(jedis);
}
/**
* 从Hash中获取对象
*/
public String hget(String key,String field){
Jedis jedis =jedisPool.getResource();
String text=jedis.hget(key,field);
jedisPool.returnResource(jedis);
return text;
}
/**
* 从Hash中获取对象,转换成制定类型
*/
publicT hget(String key,String field,Class clazz){
String text=hget(key, field);
T result=JsonUtil.parseObject(text, clazz);
return result;
}
/**
* 从Hash中删除对象
*/
public void hdel(String key,String ... field){
Jedis jedis =jedisPool.getResource();
Object result=jedis.hdel(key,field);
jedisPool.returnResource(jedis);
}
}
  3.创建注解,其实大部分数据都是以hash形式存储的(使的key易于管理),所以,注解中定义了fieldKey,用作Hash的field。



/**
* 缓存注解
* @author liudajiang
*
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
String key();
String fieldKey() ;
int expireTime() default 3600;
}
  4.定义切面,定义PointCut 表达式为注解



@Component
@Aspect
public class CacheAspect {
@Resource RedisCacheBean redis;
/**         
* 定义缓存逻辑                  
*/
@Around("@annotation(org.myshop.cache.annotation.Cacheable)")
public Object cache(ProceedingJoinPoint pjp ) {
Object result=null;
Boolean cacheEnable=SystemConfig.getInstance().getCacheEnabled();
//判断是否开启缓存
if(!cacheEnable){
try {
result= pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return result;
}
Method method=getMethod(pjp);
Cacheable cacheable=method.getAnnotation(org.myshop.cache.annotation.Cacheable.class);
String fieldKey =parseKey(cacheable.fieldKey(),method,pjp.getArgs());
//获取方法的返回类型,让缓存可以返回正确的类型
Class returnType=((MethodSignature)pjp.getSignature()).getReturnType();
//使用redis 的hash进行存取,易于管理
result= redis.hget(cacheable.key(), fieldKey,returnType);
if(result==null){
try {
result=pjp.proceed();
Assert.notNull(fieldKey);
redis.hset(cacheable.key(),fieldKey, result);
} catch (Throwable e) {
e.printStackTrace();
}
}
return result;
}
/**          * 定义清除缓存逻辑          */
@Around(value="@annotation(org.myshop.cache.annotation.CacheEvict)")
public Object evict(ProceedingJoinPoint pjp ){
//和cache类似,使用Jedis.hdel()删除缓存即可...
      }
/**
*获取被拦截方法对象
*
*MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象
*    而缓存的注解在实现类的方法上
*所以应该使用反射获取当前对象的方法对象
*/
public Method getMethod(ProceedingJoinPoint pjp){
//获取参数的类型
Object [] args=pjp.getArgs();
Class [] argTypes=new Class;
for(int i=0;i
页: [1]
查看完整版本: 使用AOP 实现Redis缓存注解,支持SPEL