使用AOP 实现Redis缓存注解,支持SPEL(转)
来源:互联网 发布:门窗cad制图软件 编辑:程序博客网 时间:2024/06/03 17:25
源文链接:http://www.cnblogs.com/DajiangDev/p/3770894.html
原来想自己实现一个,看到网上有一个和自己思路一样的实现,经试验,完美运行,感谢原作者的分享精神。
1.applicationContext.xml,配置JedisPool
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="50" /> <property name="maxIdle" value="10" /> <property name="maxWaitMillis" value="1000" /> <property name="testOnBorrow" value="true" /> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="jedisPoolConfig" /> <constructor-arg index="1" value="127.0.0.1" /> <constructor-arg index="2" value="6379" /> </bean>
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> T hget(String key,String field,Class<T> 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<args.length;i++){ argTypes[i]=args[i].getClass(); } Method method=null; try { method=pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(),argTypes); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } return method; } /** * 获取缓存的key * key 定义在注解上,支持SPEL表达式 * @param pjp * @return */ private String parseKey(String key,Method method,Object [] args){ //获取被拦截方法参数名列表(使用Spring支持类库) LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer(); String [] paraNameArr=u.getParameterNames(method); //使用SPEL进行key的解析 ExpressionParser parser = new SpelExpressionParser(); //SPEL上下文 StandardEvaluationContext context = new StandardEvaluationContext(); //把方法参数放入SPEL上下文中 for(int i=0;i<paraNameArr.length;i++){ context.setVariable(paraNameArr[i], args[i]); } return parser.parseExpression(key).getValue(context,String.class); } }
5、使用
@Transactional @Cacheable(key="getAdminByName",fieldKey="#name") public Admin getByName(String name) { return adminDao.getByUsername(name); } @Transactional @CacheEvict(key="getAdminByName",fieldKey="#admin.username") public void update(Admin admin){ adminDao.update(admin); }
效果:
0 0
- 使用AOP 实现Redis缓存注解,支持SPEL(转)
- 使用AOP 实现Redis缓存注解,支持SPEL
- 使用AOP 实现Redis缓存注解,支持SPEL
- 使用 AOP 和注解实现方法缓存
- 使用Spring AOP注解实现Redis缓存 适合复杂业务场合
- aop切面和redis实现自定义缓存注解
- java注解使用redis缓存,@Aspect aop @interface
- 深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
- 使用注解实现AOP
- 使用注解实现AOP
- 使用注解实现AOP
- Spring AOP+自定义注解实现缓存
- spring aop实现注解式缓存
- spring aop结合redis实现数据缓存
- 使用注解实现Spring aop
- spring使用注解实现AOP
- spring oauth重复点击授权后报错Cannot approve uninitialized
- LeetCode Simplify Path
- Apache2日志格式
- mongodb在java中的分页查询
- spark源码走读(1)
- 使用AOP 实现Redis缓存注解,支持SPEL(转)
- 电脑同时开有线和无线,优先使用哪个?
- ES6学习——迭代器(Iterators):内置可迭代对象汇总
- Spring Boot 环境变量读取 和 属性对象的绑定
- Ubuntu配置Mysql
- linux下redis安装
- linux动态库多层级调用
- Java中WebService实例
- LaTeX中插入Visio图片