package com.jarvis.cache.map;
import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jarvis.cache.AbstractCacheManager;
import com.jarvis.cache.exception.CacheCenterConnectionException;
import com.jarvis.cache.script.AbstractScriptParser;
import com.jarvis.cache.serializer.ISerializer;
import com.jarvis.cache.to.AutoLoadConfig;
import com.jarvis.cache.to.CacheKeyTO;
import com.jarvis.cache.to.CacheWrapper;
/**
* 使用ConcurrentHashMap管理缓存
* @author jiayu.qiu
*/
public class CachePointCut extends AbstractCacheManager {
private static final Logger logger=LoggerFactory.getLogger(CachePointCut.class);
private final ConcurrentHashMap<String, Object> cache=new ConcurrentHashMap<String, Object>();
private CacheChangeListener changeListener;
/**
* 允许不持久化变更数(当缓存变更数量超过此值才做持久化操作)
*/
private int unpersistMaxSize=0;
private Thread thread=null;
private CacheTask cacheTask=null;
/**
* 缓存持久化文件
*/
private String persistFile;
/**
* 是否在持久化:为true时,允许持久化,false,不允许持久化
*/
private boolean needPersist=true;
/**
* 是否拷贝缓存中的值:true时,是拷贝缓存值,可以避免外界修改缓存值;false,不拷贝缓存值,缓存中的数据可能被外界修改,但效率比较高。
*/
private boolean copyValue=false;
/**
* 清除和持久化的时间间隔
*/
private int clearAndPersistPeriod=60 * 1000; // 1Minutes
public CachePointCut(AutoLoadConfig config, ISerializer<Object> serializer, AbstractScriptParser scriptParser) {
super(config, serializer, scriptParser);
config.setCheckFromCacheBeforeLoad(false);
cacheTask=new CacheTask(this);
changeListener=cacheTask;
}
public synchronized void start() {
if(null == thread) {
thread=new Thread(cacheTask);
cacheTask.start();
thread.start();
}
}
@Override
public synchronized void destroy() {
super.destroy();
cacheTask.destroy();
if(thread != null) {
thread.interrupt();
}
}
@SuppressWarnings("unchecked")
@Override
public void setCache(final CacheKeyTO cacheKeyTO, final CacheWrapper<Object> result, final Method method, final Object args[]) throws CacheCenterConnectionException {
if(null == cacheKeyTO) {
return;
}
if(result.getExpire() < 0) {
return;
}
String cacheKey=cacheKeyTO.getCacheKey();
if(null == cacheKey || cacheKey.length() == 0) {
return;
}
CacheWrapper<Object> value=null;
if(copyValue) {
try {
value=(CacheWrapper<Object>)this.getCloner().deepClone(result, null);// 这里type为null,因为有可以是设置@ExCache缓存
} catch(Exception e) {
e.printStackTrace();
}
} else {
value=result;
}
SoftReference<CacheWrapper<Object>> reference=new SoftReference<CacheWrapper<Object>>(value);
String hfield=cacheKeyTO.getHfield();
if(null == hfield || hfield.length() == 0) {
cache.put(cacheKey, reference);
} else {
Object tmpObj=cache.get(cacheKey);
ConcurrentHashMap<String, SoftReference<CacheWrapper<Object>>> hash;
if(null == tmpObj) {
hash=new ConcurrentHashMap<String, SoftReference<CacheWrapper<Object>>>();
ConcurrentHashMap<String, SoftReference<CacheWrapper<Object>>> _hash=null;
_hash=(ConcurrentHashMap<String, SoftReference<CacheWrapper<Object>>>)cache.putIfAbsent(cacheKey, hash);
if(null != _hash) {
hash=_hash;
}
} else {
if(tmpObj instanceof ConcurrentHashMap) {
hash=(ConcurrentHashMap<String, SoftReference<CacheWrapper<Object>>>)tmpObj;
} else {
logger.error(method.getClass().getName() + "." + method.getName() + "中key为" + cacheKey + "的缓存,已经被占用,请删除缓存再试。");
return;
}
}
hash.put(hfield, reference);
}
this.changeListener.cacheChange();
}
@SuppressWarnings("unchecked")
@Override
public CacheWrapper<Object> get(final CacheKeyTO cacheKeyTO, final Method method, final Object args[]) throws CacheCenterConnectionException {
if(null == cacheKeyTO) {
return null;
}
String cacheKey=cacheKeyTO.getCacheKey();
if(null == cacheKey || cacheKey.length() == 0) {
return null;
}
Object obj=cache.get(cacheKey);
if(null == obj) {
return null;
}
String hfield=cacheKeyTO.getHfield();
CacheWrapper<Object> value=null;
if(null == hfield || hfield.length() == 0) {
if(obj instanceof SoftReference) {
SoftReference<CacheWrapper<Object>> reference=(SoftReference<CacheWrapper<Object>>)obj;
if(null != reference) {
value=reference.get();
}
} else if(obj instanceof CacheWrapper) {// 兼容老版本
value=(CacheWrapper<Object>)obj;
}
} else {
ConcurrentHashMap<String, Object> hash=(ConcurrentHashMap<String, Object>)obj;
Object tmp=hash.get(hfield);
if(tmp instanceof SoftReference) {
SoftReference<CacheWrapper<Object>> reference=(SoftReference<CacheWrapper<Object>>)tmp;
if(null != reference) {
value=reference.get();
}
} else if(tmp instanceof CacheWrapper) {// 兼容老版本
value=(CacheWrapper<Object>)tmp;
}
}
if(copyValue) {
try {
CacheWrapper<Object> res=new CacheWrapper<Object>();
res.setExpire(value.getExpire());
res.setLastLoadTime(value.getLastLoadTime());
res.setCacheObject(this.getCloner().deepClone(value.getCacheObject(), method.getReturnType()));
return res;
} catch(Exception e) {
e.printStackTrace();
}
}
return value;
}
@SuppressWarnings("unchecked")
@Override
public void delete(CacheKeyTO cacheKeyTO) throws CacheCenterConnectionException {
if(null == cacheKeyTO) {
return;
}
String cacheKey=cacheKeyTO.getCacheKey();
if(null == cacheKey || cacheKey.length() == 0) {
return;
}
String hfield=cacheKeyTO.getHfield();
if(null == hfield || hfield.length() == 0) {
Object tmp=cache.remove(cacheKey);
if(null == tmp) {// 如果删除失败
return;
}
if(tmp instanceof CacheWrapper) {
this.changeListener.cacheChange();
} else if(tmp instanceof ConcurrentHashMap) {
ConcurrentHashMap<String, CacheWrapper<Object>> hash=(ConcurrentHashMap<String, CacheWrapper<Object>>)tmp;
if(hash.size() > 0) {
this.changeListener.cacheChange(hash.size());
}
}
} else {
ConcurrentHashMap<String, CacheWrapper<Object>> hash=(ConcurrentHashMap<String, CacheWrapper<Object>>)cache.get(cacheKey);
if(null != hash) {
Object tmp=hash.remove(hfield);
if(null != tmp) {// 如果删除成功
this.changeListener.cacheChange();
}
}
}
}
public ConcurrentHashMap<String, Object> getCache() {
return cache;
}
public String getPersistFile() {
return persistFile;
}
public void setPersistFile(String persistFile) {
this.persistFile=persistFile;
}
public boolean isNeedPersist() {
return needPersist;
}
public void setNeedPersist(boolean needPersist) {
this.needPersist=needPersist;
}
public int getUnpersistMaxSize() {
return unpersistMaxSize;
}
public void setUnpersistMaxSize(int unpersistMaxSize) {
if(unpersistMaxSize > 0) {
this.unpersistMaxSize=unpersistMaxSize;
}
}
public boolean isCopyValue() {
return copyValue;
}
public void setCopyValue(boolean copyValue) {
this.copyValue=copyValue;
}
public int getClearAndPersistPeriod() {
return clearAndPersistPeriod;
}
public void setClearAndPersistPeriod(int clearAndPersistPeriod) {
this.clearAndPersistPeriod=clearAndPersistPeriod;
}
}