|
公司项目对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中获取对象,转换成制定类型
*/
public T 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[pjp.getArgs().length];
for(int i=0;i |
|
|