From a6d8e2d9a4679d4851666f016518cb360bb06f30 Mon Sep 17 00:00:00 2001 From: qiujiayu Date: Tue, 21 Apr 2015 15:05:21 +0800 Subject: [PATCH] =?UTF-8?q?/**=20=20=20=20=20=20*=20=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E7=9A=84=E6=93=8D=E4=BD=9C=E7=B1=BB=E5=9E=8B=EF=BC=9A=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E6=98=AFREAD=5FWRITE=EF=BC=8C=E5=85=88=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E5=8F=96=E6=95=B0=E6=8D=AE=EF=BC=8C=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E6=95=B0=E6=8D=AE=E5=88=99=E4=BB=8EDAO?= =?UTF-8?q?=E4=B8=AD=E8=8E=B7=E5=8F=96=E5=B9=B6=E5=86=99=E5=85=A5=E7=BC=93?= =?UTF-8?q?=E5=AD=98=EF=BC=9B=E5=A6=82=E6=9E=9C=E6=98=AFWRITE=E5=88=99?= =?UTF-8?q?=E4=BB=8EDAO=E5=8F=96=E5=AE=8C=E6=95=B0=E6=8D=AE=E5=90=8E?= =?UTF-8?q?=EF=BC=8C=E5=86=99=E5=85=A5=E7=BC=93=E5=AD=98=20=20=20=20=20=20?= =?UTF-8?q?*=20@return=20=20=20=20=20=20*/=20=20=20=20=20CacheOpType=20opT?= =?UTF-8?q?ype()=20default=20CacheOpType.READ=5FWRITE;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +- pom.xml | 2 +- .../jarvis/cache/AbstractCacheManager.java | 134 +++++++++++------- src/main/java/com/jarvis/cache/CacheUtil.java | 19 ++- .../com/jarvis/cache/annotation/Cache.java | 8 ++ .../cache/annotation/CacheDeleteKey.java | 2 + .../com/jarvis/cache/type/CacheOpType.java | 16 +++ 7 files changed, 143 insertions(+), 52 deletions(-) create mode 100644 src/main/java/com/jarvis/cache/type/CacheOpType.java diff --git a/README.md b/README.md index 03ad5085..46625329 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,17 @@ AutoLoadHandler(自动加载处理器)主要做的事情:当缓存即将 ##使用方法 -###1. Spring AOP配置 +###1. Maven + + + + com.github.qiujiayu + autoload-cache + 1.5 + + + +###2. Spring AOP配置 从0.4版本开始增加了Redis及Memcache的PointCut 的实现,直接在Spring 中用就可以使用。 @@ -96,7 +106,7 @@ Memcache 例子: [实例代码](https://github.com/qiujiayu/cache-example) -###2. 将需要使用缓存的方法前增加@Cache注解 +###3. 将需要使用缓存的方法前增加@Cache注解 package com.jarvis.example.dao; import ... ... diff --git a/pom.xml b/pom.xml index 731d962c..d2d28e51 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.github.qiujiayu autoload-cache - 1.4 + 1.5 jar AutoLoadCache User Spring AOP and annotation to do with cache. diff --git a/src/main/java/com/jarvis/cache/AbstractCacheManager.java b/src/main/java/com/jarvis/cache/AbstractCacheManager.java index 64655daf..8a6bca0a 100644 --- a/src/main/java/com/jarvis/cache/AbstractCacheManager.java +++ b/src/main/java/com/jarvis/cache/AbstractCacheManager.java @@ -15,6 +15,7 @@ import com.jarvis.cache.to.AutoLoadConfig; import com.jarvis.cache.to.AutoLoadTO; import com.jarvis.cache.to.CacheWrapper; +import com.jarvis.cache.type.CacheOpType; import com.jarvis.lib.util.BeanUtil; /** @@ -59,6 +60,25 @@ private String getCacheKey(ProceedingJoinPoint pjp, Cache cache) { } return cacheKey; } + /** + * 生成缓存 Key + * @param pjp + * @param cache + * @param result 执行结果值 + * @return + */ + private String getCacheKey(ProceedingJoinPoint pjp, Cache cache, T result) { + String className=pjp.getTarget().getClass().getName(); + String methodName=pjp.getSignature().getName(); + Object[] arguments=pjp.getArgs(); + String cacheKey=null; + if(null != cache.key() && cache.key().trim().length() > 0) { + cacheKey=CacheUtil.getDefinedCacheKey(cache.key(), arguments, result); + } else { + cacheKey=CacheUtil.getDefaultCacheKey(className, methodName, arguments, cache.subKeySpEL()); + } + return cacheKey; + } /** * 处理@Cache 拦截 @@ -70,20 +90,16 @@ private String getCacheKey(ProceedingJoinPoint pjp, Cache cache) { public T proceed(ProceedingJoinPoint pjp, Cache cache) throws Exception { Object[] arguments=pjp.getArgs(); if(!CacheUtil.isCacheable(cache, arguments)) {// 如果不进行缓存,则直接返回数据 - try { - @SuppressWarnings("unchecked") - T result=(T)pjp.proceed(); - return result; - } catch(Exception e) { - throw e; - } catch(Throwable e) { - throw new Exception(e); - } + return getData(pjp, null); } int expire=cache.expire(); - if(expire <= 0) { - expire=300; + if(null != cache.opType() && cache.opType() == CacheOpType.WRITE) {// 更新缓存操作 + T result=getData(pjp, null); + String cacheKey=getCacheKey(pjp, cache, result); + writeCache(result, cacheKey, expire); + return result; } + String cacheKey=getCacheKey(pjp, cache); AutoLoadTO autoLoadTO=null; if(CacheUtil.isAutoload(cache, arguments)) { @@ -106,7 +122,33 @@ public T proceed(ProceedingJoinPoint pjp, Cache cache) throws Exception { } return cacheWrapper.getCacheObject(); } + return loadData(pjp, autoLoadTO, cacheKey, expire); + } + + /** + * 写缓存 + * @param result + * @param cacheKey + * @param expire + */ + private void writeCache(T result, String cacheKey, int expire) { + CacheWrapper tmp=new CacheWrapper(); + tmp.setCacheObject(result); + tmp.setLastLoadTime(System.currentTimeMillis()); + this.setCache(cacheKey, tmp, expire); + } + /** + * 通过ProceedingJoinPoint加载数据 + * @param pjp + * @param autoLoadTO + * @param cacheKey + * @param cacheManager + * @param expire + * @return + * @throws Exception + */ + private T loadData(ProceedingJoinPoint pjp, AutoLoadTO autoLoadTO, String cacheKey, int expire) throws Exception { Boolean isProcessing=null; try { lock.lock(); @@ -116,42 +158,45 @@ public T proceed(ProceedingJoinPoint pjp, Cache cache) throws Exception { } finally { lock.unlock(); } - - if(null == isProcessing) { - return loadData(pjp, autoLoadTO, cacheKey, expire); - } - long startWait=System.currentTimeMillis(); - while(System.currentTimeMillis() - startWait < 500) { - synchronized(lock) { - try { - lock.wait(); - } catch(InterruptedException ex) { - logger.error(ex.getMessage(), ex); + T result=null; + try { + if(null == isProcessing) { + result=getData(pjp, autoLoadTO); + } else { + long startWait=System.currentTimeMillis(); + while(System.currentTimeMillis() - startWait < 500) {// 等待 + synchronized(lock) { + try { + lock.wait(); + } catch(InterruptedException ex) { + logger.error(ex.getMessage(), ex); + } + } + if(null == processing.get(cacheKey)) {// 防止频繁去缓存取数据,造成缓存服务器压力过大 + CacheWrapper cacheWrapper=this.get(cacheKey); + if(cacheWrapper != null) { + return cacheWrapper.getCacheObject(); + } + } } + result=getData(pjp, autoLoadTO); } - if(null == processing.get(cacheKey)) {// 防止频繁去缓存取数据,造成缓存服务器压力过大 - cacheWrapper=this.get(cacheKey); - if(cacheWrapper != null) { - return cacheWrapper.getCacheObject(); - } + } catch(Exception e) { + throw e; + } catch(Throwable e) { + throw new Exception(e); + } finally { + processing.remove(cacheKey); + synchronized(lock) { + lock.notifyAll(); } } - return loadData(pjp, autoLoadTO, cacheKey, expire); + writeCache(result, cacheKey, expire); + return result; } - /** - * 通过ProceedingJoinPoint加载数据 - * @param pjp - * @param autoLoadTO - * @param cacheKey - * @param cacheManager - * @param expire - * @return - * @throws Exception - */ - private T loadData(ProceedingJoinPoint pjp, AutoLoadTO autoLoadTO, String cacheKey, int expire) throws Exception { + private T getData(ProceedingJoinPoint pjp, AutoLoadTO autoLoadTO) throws Exception { try { - AutoLoadConfig config=autoLoadHandler.getConfig(); if(null != autoLoadTO) { autoLoadTO.setLoading(true); } @@ -159,14 +204,11 @@ private T loadData(ProceedingJoinPoint pjp, AutoLoadTO autoLoadTO, String cacheK @SuppressWarnings("unchecked") T result=(T)pjp.proceed(); long useTime=System.currentTimeMillis() - startTime; + AutoLoadConfig config=autoLoadHandler.getConfig(); if(config.isPrintSlowLog() && useTime >= config.getSlowLoadTime()) { String className=pjp.getTarget().getClass().getName(); logger.error(className + "." + pjp.getSignature().getName() + ", use time:" + useTime + "ms"); } - CacheWrapper tmp=new CacheWrapper(); - tmp.setCacheObject(result); - tmp.setLastLoadTime(System.currentTimeMillis()); - this.setCache(cacheKey, tmp, expire); if(null != autoLoadTO) { autoLoadTO.setLastLoadTime(startTime); autoLoadTO.addUseTotalTime(useTime); @@ -180,10 +222,6 @@ private T loadData(ProceedingJoinPoint pjp, AutoLoadTO autoLoadTO, String cacheK if(null != autoLoadTO) { autoLoadTO.setLoading(false); } - processing.remove(cacheKey); - synchronized(lock) { - lock.notifyAll(); - } } } diff --git a/src/main/java/com/jarvis/cache/CacheUtil.java b/src/main/java/com/jarvis/cache/CacheUtil.java index 06028540..36022eab 100644 --- a/src/main/java/com/jarvis/cache/CacheUtil.java +++ b/src/main/java/com/jarvis/cache/CacheUtil.java @@ -21,6 +21,8 @@ public class CacheUtil { private static final String ARGS="args"; + private static final String RET_VAL="retVal"; + private static final ExpressionParser parser=new SpelExpressionParser(); private static final Pattern pattern_hash=Pattern.compile("(\\+?)\\$hash\\((.[^)]*)\\)"); @@ -101,7 +103,7 @@ public static T getElValue(String keySpEL, Object[] arguments, Object retVal m.appendTail(sb); EvaluationContext context=new StandardEvaluationContext(); context.setVariable(ARGS, arguments); - context.setVariable("retVal", retVal); + context.setVariable(RET_VAL, retVal); return parser.parseExpression(sb.toString()).getValue(context, valueType); } @@ -119,6 +121,21 @@ public static String getDefinedCacheKey(String keySpEL, Object[] arguments) { } } + /** + * 根据请求参数和执行结果值,进行构造缓存Key + * @param keySpEL + * @param arguments + * @param retVal + * @return + */ + public static String getDefinedCacheKey(String keySpEL, Object[] arguments, Object retVal) { + if(keySpEL.indexOf("#" + ARGS) != -1 || keySpEL.indexOf("#" + RET_VAL) != -1) { + return getElValue(keySpEL, arguments, retVal, String.class); + } else { + return keySpEL; + } + } + /** * 生成缓存Key * @param className 类名称 diff --git a/src/main/java/com/jarvis/cache/annotation/Cache.java b/src/main/java/com/jarvis/cache/annotation/Cache.java index 1e76d0f5..db75079a 100644 --- a/src/main/java/com/jarvis/cache/annotation/Cache.java +++ b/src/main/java/com/jarvis/cache/annotation/Cache.java @@ -5,6 +5,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import com.jarvis.cache.type.CacheOpType; + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Cache { @@ -49,4 +51,10 @@ * @return */ String condition() default ""; + + /** + * 缓存的操作类型:默认是READ_WRITE,先缓存取数据,如果没有数据则从DAO中获取并写入缓存;如果是WRITE则从DAO取完数据后,写入缓存 + * @return + */ + CacheOpType opType() default CacheOpType.READ_WRITE; } \ No newline at end of file diff --git a/src/main/java/com/jarvis/cache/annotation/CacheDeleteKey.java b/src/main/java/com/jarvis/cache/annotation/CacheDeleteKey.java index 90c07c68..3d6b5a89 100644 --- a/src/main/java/com/jarvis/cache/annotation/CacheDeleteKey.java +++ b/src/main/java/com/jarvis/cache/annotation/CacheDeleteKey.java @@ -10,11 +10,13 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface CacheDeleteKey { + /** * 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 * @return */ String condition() default ""; + /** * 删除缓存的Key,支持使用SpEL表达式 * @return diff --git a/src/main/java/com/jarvis/cache/type/CacheOpType.java b/src/main/java/com/jarvis/cache/type/CacheOpType.java new file mode 100644 index 00000000..b71dacb0 --- /dev/null +++ b/src/main/java/com/jarvis/cache/type/CacheOpType.java @@ -0,0 +1,16 @@ +package com.jarvis.cache.type; + +/** + * 缓存操作类型 + * @author jarvis + */ +public enum CacheOpType { + /** + * 读写缓存操 + */ + READ_WRITE, + /** + * 只往缓存写数据,不从缓存中读数据 + */ + WRITE; +}