- 浏览: 300573 次
- 性别:
文章分类
最新评论
-
u010503822:
不懂这个是否是你需要的// map转Json数据 json转 ...
gson使用感受 -
亚飞正传:
您好,你以前是在PChome工作的?
<![CDATA[谈谈PHP为什么不支持重载和多态]]> -
亚飞正传:
您好,你以前是在PChome工作的?
<![CDATA[谈谈PHP为什么不支持重载和多态]]> -
wangluo19:
对T解释的很清楚,以前看到java源码中的T就晕了,现在好了明 ...
JAVA学习笔记之泛型接口 -
huangfoxAgain:
不错!!!
JAVA学习笔记之泛型接口
缓存的实现最简单的模式,我称作为get set invalid 法,这也是缓存中最常用的一种模式,以前实现缓存(特别是后加)一般都会写一大堆诸如:
Object target = cache.get(KEY) if(target!=null){ //do something }else{ //do set }
这个其实很不好看,代码很不优雅.当然你可以使用一些设计模式去解决比如说圆盘套圆盘法---函数模板...但实现起来并那么容易有时候会导致代码可读性下降,而且缓存的key可能一样不灵活.
现在好了,我们可以尝试用SPRING的AOP来做:
<?xml version="1.0" encoding="gbk"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd" default-autowire="byName"> <bean id="AopManagerForCache" class="org.edwardpro.common.aop.CacheAOPManagerImpl"> <property name="expTime"> <value>900</value> </property> </bean> <aop:config> <aop:aspect id="dataAOP" ref="AopManagerForCache"> <aop:around pointcut="execution(* org.edwardpro.aop.biz.core.manager.*Manager.*(..))" method="checkJointPoint" /> </aop:aspect> </aop:config> </beans>
这样在指定包的地方都会被拦截,方法被拦截了干什么还是一个问题,这里我使用了注入,一共有两类注入,一种叫CheckCache一种叫FlushCache.Flush是用来delete缓存的 checkcache是用来检查缓存的,典型的get时候用check而update时候用flush.由于缓存key是来自于参数的,所以这个注解我定义了三个参数:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface CacheCheck { /** * 缓存的前缀,就是缓存那些参数前面的修饰符号: MSP_SHOP_SHOPINFO * * 这个字段支持表达式了,表达式的含义是最后输出的前缀是什么并会影响整个键值生成系统 * 表达式的样例: * expr:{0 equa} * @return */ public String cachePrefix(); /** * 活动参数的表达式,这个需要用拦截器获得的,这里只是把参数列举出来,最终的形式: _{value}_ * * 如果是复杂对象,使用 0.aaa 1 2.ccc的形式来写 * * * @return */ public String[] paramList(); /** * New Add * * 有些缓存刷新需要返回值,比如分页缓存的刷新 方便起见格式用json写: * * {'isRange':'0','range-start':'1','range-end':'10','range-step':'1'} * * @return */ public String range(); }
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface FlushCache { /** * 缓存的前缀,就是缓存那些参数前面的修饰符号: MSP_SHOP_SHOPINFO * * @return */ public String[] cachePrefix(); /** * 活动参数的表达式,这个需要用拦截器获得的,这里只是把参数列举出来,最终的形式: _{value}_ * * 如果是复杂对象,使用 0.aaa 1 2.ccc的形式来写 * * * @return */ public String[] paramList(); /** * New Add * * 有些缓存刷新需要返回值,比如分页缓存的刷新 方便起见格式用json写: * * {'isRange':'0','range-start':'1','range-end':'10','range-step':'1'} * * @return */ public String[] range(); }
参数的表达是这样的 (0.xx) xx一定是要set get方法的属性值,因为我的实现依赖于beanutil. 0,1,2 是参数的位置,因为在aop后参数名没有了,虽然也有方法可以得到,但是那个很麻烦,省事期间我还是用0,1,2这种表示是哪个参数,下面看下解析参数用的类:
/** * aop的工具之一用来通过参数表解析式得到参数信息 * * @param paramStr * @param obj * @return paramStr 最简单形式是 0 0.aa */ public static List<Object> getValueByStr(String paramStr, Object[] obj) { List<Object> ret = new ArrayList<Object>(); String[] args = paramStr.split("\\."); if (args != null && args.length >= 1) { // 原始对象 Object valueOrg = obj[Integer.parseInt(args[0])]; if (valueOrg instanceof Collection) { for (Object childObj : (Collection) valueOrg) { if (args.length == 1) { ret.add(childObj); continue; } for (int i = 1; i < args.length; i++) { PropertyDescriptor pd = BeanUtils .getPropertyDescriptor(childObj.getClass(), args[i]); try { // 增加容错代码 if (pd != null) { childObj = pd.getReadMethod().invoke(childObj); } if (i == (args.length - 1)) { ret.add(childObj); } } catch (IllegalArgumentException e) { continue; } catch (IllegalAccessException e) { continue; } catch (InvocationTargetException e) { continue; } } } } else { if (args.length == 1) { ret.add(valueOrg); } for (int i = 1; i < args.length; i++) { PropertyDescriptor pd = BeanUtils.getPropertyDescriptor( valueOrg.getClass(), args[i]); try { // 增加容错代码 if (pd != null) { valueOrg = pd.getReadMethod().invoke(valueOrg); } if (i == (args.length - 1)) { ret.add(valueOrg); } } catch (IllegalArgumentException e) { continue; } catch (IllegalAccessException e) { continue; } catch (InvocationTargetException e) { continue; } } } // return valueOrg; } return ret;
代码比较粗俗随便看看就是了~_~
然后差不多把这些组合起来:
/* * (non-Javadoc) * * @seecom.taobao.common.aop.CacheAOPManager#checkCache(org.aspectj.lang. * ProceedingJoinPoint, com.taobao.common.annotation.cache.CacheCheck) */ @Override public Object checkCache(ProceedingJoinPoint jointPoint, CacheCheck cacheCheck) { String key = this.getCheckKey(cacheCheck, jointPoint.getArgs()); Result<DataEntry> ret = this.getTairManager().get(this.getNameSpace(), key); logger.info(">>checkValue>>" + ret.getRc().getMessage()); if (ret != null && ret.getRc().getCode() == 0) { Object obj = ret.getValue().getValue(); return obj; } else { try { // 没有得到缓存所以会执行对象 logger.info(">>checkValue>>No Cache"); Object obj = jointPoint.proceed(); ResultCode retCode = this.getTairManager().put( this.getNameSpace().intValue(), key, (Serializable) obj, 0, this.getExpTime()); logger.info("set cache result>>" + retCode.getCode() + "|" + retCode.getMessage()); return obj; } catch (Throwable e) { logger.error(e); } } return null; }
/* * (non-Javadoc) * * @seecom.taobao.common.aop.CacheAOPManager#flushCache(org.aspectj.lang. * ProceedingJoinPoint, com.taobao.common.annotation.cache.FlushCache) */ @Override public Object flushCache(ProceedingJoinPoint jointPoint, FlushCache flushCache) { List<Object> keyList = this.getFlushKey(flushCache, jointPoint .getArgs()); ResultCode ret = this.tairManager.mdelete(this.getNameSpace() .intValue(), keyList); logger.info(">>flush cache result>>" + keyList + ">>" + ret.getCode() + ">>" + ret.getMessage()); try { return jointPoint.proceed(); } catch (Throwable e) { logger.error(e); } return null; }
/** * 通过参数得到前缀 * * @param flushCache * @param args * @return */ public List<Object> getFlushKey(FlushCache flushCache, Object[] args) { List<Object> ret = new ArrayList<Object>(); if (flushCache != null) { for (int i = 0; i < flushCache.cachePrefix().length; i++) { String prefix = flushCache.cachePrefix()[i]; List<String> paramList = this.genParamList(flushCache, i, args, prefix); List<String> rangeList = this.genRange(flushCache, i); for (String paramItem : paramList) { if (rangeList.size() > 0) { for (String rangeItem : rangeList) { StringBuilder sb = new StringBuilder(); sb.append(paramItem); sb.append(rangeItem); ret.add(sb.toString()); } } else { // StringBuilder sb = new StringBuilder(); // sb.append(paramItem); ret.add(paramItem); } } } this.removeDuplicated(ret); } return ret; } private List<String> genParamList(FlushCache flushCache, int index, Object[] args, String prefix) { List<String> ret = new ArrayList<String>(); List<String> paramList; if (index <= (flushCache.paramList().length - 1)) { // 对应的关系 paramList = this.getPrefix(flushCache.paramList()[index]); } else { paramList = this.getPrefix(flushCache.paramList()[0]); } for (String argStr : paramList) { List<Object> argsValue = valueProcessManager.getValue(argStr, args); if (ret.size() > 0) { List<String> tempRet = new ArrayList<String>(); for (String tempItem : ret) { for (Object tempObj : argsValue) { StringBuilder sbTemp = new StringBuilder(); sbTemp.append(tempItem); sbTemp.append(KEY_SPILIT); sbTemp.append(tempObj); tempRet.add(sbTemp.toString()); } } ret.clear(); ret.addAll(tempRet); } else { for (Object item : argsValue) { ret.add(prefix + KEY_SPILIT + item.toString()); } } } if (ret.size() == 0) { ret.add(prefix + KEY_SPILIT); } return ret; } private List<String> genRange(FlushCache flushCache, int index) { List<String> ret = new ArrayList<String>(); if (null != flushCache.range()) { String range; if (index <= (flushCache.range().length - 1)) { // 对应的关系 range = flushCache.range()[index]; } else { range = flushCache.range()[0]; } Map<String, Integer> map = JsonUtils.mapFromJson(range, Integer.class); KeyRanger keyRanger = KeyRanger.getInstance(map); if (keyRanger.getIsRange() > 0) { for (int j = keyRanger.getRangeStart(); j <= keyRanger .getRangeEnd(); j = j + keyRanger.getRangeStep()) { StringBuilder sb = new StringBuilder(); sb.append(KEY_SPILIT); sb.append(j); ret.add(sb.toString()); } } } return ret; } // 去除重复KEY private void removeDuplicated(List<Object> input) { List<Object> tempList = new ArrayList<Object>(input); HashSet<Object> tempSet = new HashSet<Object>(tempList); input.clear(); for (Object obj : tempSet) { input.add(obj); } } public String getCheckKey(CacheCheck cacheCheck, Object[] args) { StringBuffer ret = new StringBuffer(); ret.append(cacheCheck.cachePrefix()); for (String argStr : cacheCheck.paramList()) { List<Object> argsValue = valueProcessManager.getValue(argStr, args); if (argsValue != null) { for (Object oChild : argsValue) { if (oChild != null) { ret.append(KEY_SPILIT); ret.append(oChild); } } } } logger.info(ret.toString()); return ret.toString(); } private List<String> getPrefix(String keys) { List<String> ret = new ArrayList<String>(); if (null != keys) { String[] arr = keys.split(","); if (null != arr) { for (String s : arr) { if (!TBStringUtil.isBlank(s)) { ret.add(s); } } } } return ret; }
变成贴代码了....天太热不想多打字,呵呵,大家凑合看,基本上看下spring配置就知道大概的意图了,试用下来对于一般的前后台应用足够了,但是要注意,拦截的方法一定是要业务层的,另外前后台的get方法最好分开,否则缓存一旦配置有问题,就会导致后台更新不了的故障,这个要注意...
over,其实只是想提供一种思路至于实现就贻笑大方了...
发表评论
-
Thread In Ruby
2011-11-02 00:24 2572今日终于把原来留下来的ios notify给整了,由于用户数据 ... -
thrift-1-2-3
2011-10-07 20:24 3960国庆前后玩了一下thrift,下面是一些入门级的体会和心得: ... -
lexer html解析一个js过滤的改进
2011-09-22 11:07 1251问题描述,使用htmlparser的lexer解析器进行页面解 ... -
在linux下删除大文件的好方法
2011-09-16 09:36 2059上次在linux书上看到的,我们平时删除日志可能会用: ... -
thrift 在ubuntu 11.04下的编译过程一两点心得
2011-09-14 21:46 2918今天需要使用thrift于是随手下载下来了,下载过程很简单,但 ... -
StringBuilder和String中的subString方法的细微差别
2011-02-23 20:19 7681昨天改了一个很小的地方,但是在线上跑的时候突然感觉内存消耗差别 ... -
用枚举来作为配置
2010-04-20 21:39 1270一个简单的需求需要自动抓取一些http request参数到上 ... -
装箱操作需注意
2009-10-24 15:25 1043近期在工作里发现一个代码bug,主要是装箱上的问题,我们知道在 ... -
在JTIDY中对于inline标签的这行问题
2009-09-24 16:40 1255在一个项目中需要使用jtidy格式化页面,一开始感觉不错,但是 ... -
JAVA7的不兼容表现
2009-09-06 17:49 10164今天有时间玩一下JAVA7,却发现有点小问题: Caused ... -
gson使用感受
2009-06-13 08:27 4691google的东西向来以简洁唯美gson也是如此: ... -
数据对象化的思考
2009-06-13 07:51 1182以前曾经想利用json作为字段数据存储格式,这样当我们扩展表属 ... -
用json作为配置存储介质的讨论
2009-04-02 20:57 1286为什么会考虑json: 有没 ... -
JAVA学习笔记之泛型接口
2009-02-02 22:58 11005应该是我很久没有好好学技术了,有时候想用的时候却发现不会写,比 ... -
lucene中的filter器群组及其缓存大盘点
2008-07-04 02:13 3311lucene中的filter其实并不起眼,大家对其对性能的影响 ... -
lucene的前端集群思路
2008-04-17 10:52 4902你的搜索可以集群吗(这里单指前端应用集群)?这是一个突然发来的 ... -
lunece 用的高亮类
2007-08-10 10:12 1363网上有很多高亮的类,但我觉得太负责了(也许他们觉得这样性能更高 ... -
自己写的lucene的高亮类
2007-08-10 16:03 2091网上有很多高亮的类,但我觉得太负责了(也许他们觉得这样性能更高 ... -
使用form dom要注意的小问题
2007-08-08 16:43 1373几天调一个js遇到灵异问题:var s=$('sform'); ... -
ubuntu 7.04 下配置 ruby环境
2007-07-01 16:26 1700其实这个环境配置很容易的应该 apt-get就可以得到了,但事 ...
相关推荐
本代码通过使用spring aop+ehcache的技术,实现了方法级别的查询缓存,主要原理是 方法的完整路径+方法参数值,作为key,放入cache中,下次访问时先判断cache中是否有该key.
主要介绍了Spring AOP实现Redis缓存数据库查询的相关内容,源码部分还是不错的,需要的朋友可以参考下。
spring aop 自定义缓存实现的一个小实例,地址:http://blog.csdn.net/maoyeqiu/article/details/50260357
NULL 博文链接:https://honda418.iteye.com/blog/354945
需要使用Spring来实现一个Cache简单的解决方案,具体需求如下:使用任意一个现有开源Cache Framework,要求可以Cache系统中Service或则DAO层的get/find等方法返回结果,如果数据更新(使用Create/update/delete方法...
主要给大家介绍了关于Spring AOP如何整合redis(注解方式)实现缓存统一管理的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧
主要介绍了浅谈SpringBoot集成Redis实现缓存处理(Spring AOP实现),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
它主要由Beans模块、Core模块、Context模块、Context-support模块和SpEL(Spring Expression Language,Spring表达式语言)模块组成,具体介绍如下: Beans模块:提供了BeanFactory,是工厂模式的经典实现,Spring将...
NULL 博文链接:https://leiwuluan.iteye.com/blog/1176120
主要是利用Spring AOP实现动态数据源,和数据缓存操作。
缘起需求:需要使用Spring来实现一个Cache简单的解决方案,具体需求如下:使用任意一个现有开源Cache Framework,要求可以Cache系统中Service或者DAO层的get/find等方法返回结果,如果数据更新(使用Create/update/...
spring-**cntext**-4.3.6.RELEASE.jar:spring提供了基础IOC功能上的扩展服务,提供了很多企业级服务的支持,如邮件服务,任务调度,JNDI定位,EJB集成,远程访问,缓存以及各种试图层框架的封装等。 spring-...
下载分设置的比较高,不过绝对的...为了在接下来的项目中能够方便的控制和使用 redis,所以也粗略的模仿了下membercache的aop代码,写了一份spring-redis-aop。当然方法有很多种,也许你有更好的 使用方法当然更好哈。
2、Spring Cache利用了AOP,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了,做到了对代码侵入性做小。 3、由于市面上的...
spring中使用缓存的方案,根据需求,使用Spring AOP + ehCache可实现些功能,使用EHCACHE能方便地结合SPRING来实现缓存。
概述Spring Aop在Spring框架中的布局举足轻重,主要用于实现事务,缓存,安全等功能。主要介绍以下三个方面: Spring AOP多种代理机制相关核心类介绍。 Spring Boot中AOP注解方式源码分析。 Spring Boot 1.x版本和2...
redis客户端集成spring实现aop方式,方便在程序中使用spring的时候更加方便的使用redis内存数据库, 采用aop的方式主要是为了不去污染业务代码,达到业务逻辑更加清晰易于阅读,在使用过程中可以设置 key的有效时间,...
今天小编就为大家分享一篇关于SpringBoot AOP控制Redis自动缓存和更新的示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧