Skip to content

Commit

Permalink
/**
Browse files Browse the repository at this point in the history
     * 缓存的操作类型:默认是READ_WRITE,先缓存取数据,如果没有数据则从DAO中获取并写入缓存;如果是WRITE则从DAO取完数据后,写入缓存
     * @return
     */
    CacheOpType opType() default CacheOpType.READ_WRITE;
  • Loading branch information
qiujiayu committed Apr 21, 2015
1 parent a39e730 commit a6d8e2d
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 52 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ AutoLoadHandler(自动加载处理器)主要做的事情:当缓存即将

##使用方法

###1. Spring AOP配置
###1. Maven


<dependency>
<groupId>com.github.qiujiayu</groupId>
<artifactId>autoload-cache</artifactId>
<version>1.5</version>
</dependency>


###2. Spring AOP配置


从0.4版本开始增加了Redis及Memcache的PointCut 的实现,直接在Spring 中用<aop:config>就可以使用。
Expand Down Expand Up @@ -96,7 +106,7 @@ Memcache 例子:
[实例代码](https://github.com/qiujiayu/cache-example)


###2. 将需要使用缓存的方法前增加@Cache注解
###3. 将需要使用缓存的方法前增加@Cache注解

package com.jarvis.example.dao;
import ... ...
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.qiujiayu</groupId>
<artifactId>autoload-cache</artifactId>
<version>1.4</version>
<version>1.5</version>
<packaging>jar</packaging>
<name>AutoLoadCache</name>
<description>User Spring AOP and annotation to do with cache.</description>
Expand Down
134 changes: 86 additions & 48 deletions src/main/java/com/jarvis/cache/AbstractCacheManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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 拦截
Expand All @@ -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)) {
Expand All @@ -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<T> tmp=new CacheWrapper<T>();
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();
Expand All @@ -116,57 +158,57 @@ 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<T> 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);
}
long startTime=System.currentTimeMillis();
@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<T> tmp=new CacheWrapper<T>();
tmp.setCacheObject(result);
tmp.setLastLoadTime(System.currentTimeMillis());
this.setCache(cacheKey, tmp, expire);
if(null != autoLoadTO) {
autoLoadTO.setLastLoadTime(startTime);
autoLoadTO.addUseTotalTime(useTime);
Expand All @@ -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();
}
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/main/java/com/jarvis/cache/CacheUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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\\((.[^)]*)\\)");
Expand Down Expand Up @@ -101,7 +103,7 @@ public static <T> 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);
}

Expand All @@ -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 类名称
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/com/jarvis/cache/annotation/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -49,4 +51,10 @@
* @return
*/
String condition() default "";

/**
* 缓存的操作类型:默认是READ_WRITE,先缓存取数据,如果没有数据则从DAO中获取并写入缓存;如果是WRITE则从DAO取完数据后,写入缓存
* @return
*/
CacheOpType opType() default CacheOpType.READ_WRITE;
}
2 changes: 2 additions & 0 deletions src/main/java/com/jarvis/cache/annotation/CacheDeleteKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheDeleteKey {

/**
* 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存
* @return
*/
String condition() default "";

/**
* 删除缓存的Key,支持使用SpEL表达式
* @return
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/jarvis/cache/type/CacheOpType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.jarvis.cache.type;

/**
* 缓存操作类型
* @author jarvis
*/
public enum CacheOpType {
/**
* 读写缓存操
*/
READ_WRITE,
/**
* 只往缓存写数据,不从缓存中读数据
*/
WRITE;
}

0 comments on commit a6d8e2d

Please sign in to comment.