package com.walker.cache;
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.walker.cache.util.KeyUtils;
|
import com.walker.infrastructure.core.ApplicationBeanDestroied;
|
import com.walker.infrastructure.core.ApplicationBeanInitialized;
|
import com.walker.infrastructure.utils.Assert;
|
import com.walker.infrastructure.utils.ObjectStreamUtils;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.HashSet;
|
import java.util.Iterator;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* <p/>抽象的内存缓存对象,以纯内存方式管理缓存的基类
|
* @author MikeShi
|
*
|
*/
|
public abstract class AbstractMemoryCache implements Cache, ApplicationBeanInitialized, ApplicationBeanDestroied {
|
|
/**
|
*
|
*/
|
private static final long serialVersionUID = 2575070748765281205L;
|
|
// protected final transient Log logger = LogFactory.getLog(this.getClass());
|
protected final transient Logger logger = LoggerFactory.getLogger(this.getClass());
|
|
ConcurrentHashMap<String, Cachable> cacheMap = new ConcurrentHashMap<String, Cachable>(CacheConfig.INIT_CACHEMAP_SIZE);
|
|
private String cacheName;
|
|
public long expiredTime = 0;
|
|
private boolean writeOnDiskAfterShutdown = false;
|
|
private CacheOperateListener cacheOperateListener = null;
|
|
private boolean hasCacheListener = false;
|
|
public void setCacheOperateListener(CacheOperateListener cacheOperateListener) {
|
if(cacheOperateListener != null){
|
hasCacheListener = true;
|
}
|
this.cacheOperateListener = cacheOperateListener;
|
}
|
|
public AbstractMemoryCache(){}
|
|
public String getCacheName() {
|
return cacheName;
|
}
|
|
public void setCacheName(String name) {
|
this.cacheName = name;
|
}
|
|
public long getExpiredTime() {
|
return expiredTime;
|
}
|
|
public void setExpiredTime(int seconds) {
|
this.expiredTime = seconds*1000;
|
}
|
|
public Iterator<Cachable> getIterator(){
|
synchronized (cacheMap) {
|
return cacheMap.values().iterator();
|
}
|
}
|
|
@SuppressWarnings("unchecked")
|
public void startup() {
|
logger.debug("........ execute startup in AbstractMemoryCache! cacheName = " + cacheName);
|
Assert.isTrue(cacheName != null && !cacheName.equals(""));
|
if(writeOnDiskAfterShutdown){
|
Object obj = ObjectStreamUtils.readObjectFromFile(CacheConfig.WRITE_TEMP_CACHEFILE + cacheName);
|
if(obj != null){
|
logger.info("load cache data from disk! cache name: " + cacheName);
|
cacheMap = (ConcurrentHashMap<String, Cachable>)obj;
|
}
|
}
|
}
|
public void shutdown() {
|
logger.debug("........ execute shutdown in AbstractMemoryCache! cacheName = " + cacheName);
|
if(writeOnDiskAfterShutdown && !cacheMap.isEmpty()){
|
ObjectStreamUtils.writeObjectToFile(CacheConfig.WRITE_TEMP_CACHEFILE + cacheName, cacheMap);
|
}
|
cacheMap.clear();
|
cacheMap = null;
|
cacheName = null;
|
}
|
|
public boolean isWriteOnDiskAfterShutdown() {
|
return writeOnDiskAfterShutdown;
|
}
|
|
public void setWriteOnDiskAfterShutdown(boolean boo) {
|
writeOnDiskAfterShutdown = boo;
|
}
|
|
public String toString(){
|
StringBuilder sb = new StringBuilder();
|
sb.append("[cacheName=");
|
sb.append(cacheName);
|
sb.append(", expiredTime=");
|
sb.append(expiredTime);
|
sb.append(", cacheSize=");
|
sb.append(cacheMap.size());
|
sb.append(", data=");
|
sb.append(cacheMap);
|
sb.append("]");
|
return sb.toString();
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// cache data operations
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
/**
|
* 根据key,从缓存取出一个用户数据
|
*/
|
public Object get(String key) {
|
// public T get(String key) {
|
// logger.debug("----------" + cacheMap.get(key).isExpired(System.currentTimeMillis(), expiredTime));
|
Cachable d = cacheMap.get(key);
|
if(d != null){
|
return d.getValue();
|
}
|
return null;
|
}
|
|
/**
|
* 放入缓存一条新数据
|
*/
|
public void put(String key, Object data) {
|
Assert.notNull(key);
|
Assert.notNull(data);
|
|
// synchronized (cacheMap) {
|
Cachable cacheData = new CacheData();
|
cacheData.setKey(key);
|
cacheData.setValue(data);
|
|
cacheMap.put(key, cacheData);
|
if(hasCacheListener){
|
cacheOperateListener.onPut(data);
|
}
|
// }
|
}
|
|
/**
|
* 放入缓存数据有时间有效期
|
* @param key
|
* @param data
|
* @param expiredSeconds 过期秒数
|
* @date 2022-11-06
|
*/
|
public void put(String key, Object data, long expiredSeconds){
|
throw new UnsupportedOperationException("该方法由<code>RedisCache</code>或者业务自定义CacheProvider实现。");
|
}
|
|
/**
|
* 删除一条缓存数据
|
*/
|
public Object remove(String key) {
|
// synchronized (cacheMap){
|
Cachable c = cacheMap.remove(key);
|
if(c != null){
|
Object v = c.getValue();
|
if(hasCacheListener){
|
cacheOperateListener.onRemove(v);
|
}
|
return v;
|
}
|
return null;
|
// }
|
}
|
|
/**
|
* 替换key相同的缓存数据为data
|
*/
|
public void replace(String key, Object data) {
|
// synchronized (cacheMap) {
|
Cachable cacheData = cacheMap.get(key);
|
if(cacheData != null){
|
cacheData.setValue(data);
|
cacheData.setTimeStamp(System.currentTimeMillis());
|
cacheData.hit();
|
}
|
// }
|
}
|
|
/**
|
* 根据数据key,更新缓存数据时间戳
|
*/
|
public void updateCacheDataTimeStamp(String key) {
|
Cachable c = cacheMap.get(key);
|
if(c != null){
|
c.setTimeStamp(System.currentTimeMillis());
|
c.hit();
|
} else
|
logger.warn("updateCacheDataTimeStamp error: cache data not found! key = " + key);
|
}
|
|
/**
|
* 删除给定的列表数据,从缓存对象中
|
*/
|
public void remove(List<String> keys) {
|
Assert.notNull(keys);
|
synchronized (cacheMap){
|
for(String key : keys){
|
cacheMap.remove(key);
|
}
|
}
|
}
|
|
/**
|
* 清除缓存数据
|
*/
|
public void clear(){
|
cacheMap.clear();
|
if(hasCacheListener){
|
cacheOperateListener.onClear();
|
}
|
}
|
|
public Object get(String key, Class<?> clazz) {
|
throw new UnsupportedOperationException();
|
}
|
|
public List<String> getIterator(Class<?> clazz) {
|
throw new UnsupportedOperationException();
|
}
|
|
public long getPersistentSize() {
|
return 0;
|
}
|
|
@Override
|
public long size(){
|
return cacheMap.size();
|
}
|
|
/**
|
* 返回给定限制的缓存数据集合
|
* @param maxSize 限制的最大数量
|
* @return
|
*/
|
@Override
|
public Collection<Object> queryListLimit(int maxSize){
|
if(maxSize < 0 || maxSize >=Integer.MAX_VALUE){
|
return null;
|
}
|
|
if(cacheMap.size() <= maxSize){
|
ObjectMapper mapper = new ObjectMapper();
|
// 当缓存数量小于给定限制,显示全部
|
List<Object> resultList = new ArrayList<>(cacheMap.size());
|
String json = null;
|
for(Cachable c : cacheMap.values()){
|
try {
|
json = mapper.writeValueAsString(c.getValue());
|
resultList.add(json);
|
} catch (JsonProcessingException e) {
|
throw new RuntimeException(e);
|
}
|
// resultList.add(JSONObject.toJSON(c.getValue()).toString());
|
}
|
return resultList;
|
|
} else {
|
//
|
throw new IllegalArgumentException("缓存数量大于给定的限制值,不能显示数据,数量过大");
|
}
|
}
|
|
@Override
|
public Set<Object> getKeys() {
|
Set<Object> keyList = new HashSet<>();
|
for(Iterator<String> it = this.cacheMap.keySet().iterator(); it.hasNext();){
|
keyList.add(it.next());
|
}
|
return keyList;
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
//~ 2023-06-13 操作集合,但目前没有使用,感觉删除整个集合还比较麻烦。
|
//~ 2023-06-14 确定使用该对象,并测试结果。
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
private ConcurrentHashMap<String, List> listMap = new ConcurrentHashMap<>(CacheConfig.INIT_CACHEMAP_SIZE);
|
|
@Override
|
public void putList(String key, List<Object> data, long expiredSeconds){
|
this.listMap.put(this.acquireListKey(key), data);
|
}
|
|
@Override
|
public void putListAppend(String key, Object data){
|
List list = this.listMap.get(this.acquireListKey(key));
|
if(list == null){
|
list = new ArrayList();
|
this.listMap.put(this.acquireListKey(key), list);
|
}
|
list.add(data);
|
}
|
|
@Override
|
public List<Object> getList(String key, long start, long end, Class<?> clazz){
|
return this.listMap.get(this.acquireListKey(key));
|
}
|
|
@Override
|
public void removeList(String key, Object value){
|
List list = this.listMap.get(this.acquireListKey(key));
|
if(list != null){
|
Object obj = null;
|
for(Iterator<Object> it = list.iterator(); it.hasNext();){
|
obj = it.next();
|
if(value.equals(obj)){
|
it.remove();
|
}
|
}
|
}
|
}
|
|
/**
|
* 根据Key 删除对应整个集合。
|
* @param key
|
* @date 2023-08-03
|
*/
|
@Override
|
public void removeList(String key){
|
this.listMap.remove(this.acquireListKey(key));
|
}
|
|
@Override
|
public long getListSize(String key){
|
List list = this.listMap.get(this.acquireListKey(key));
|
if(list == null){
|
return 0;
|
}
|
return list.size();
|
}
|
|
private String acquireListKey(String key){
|
return KeyUtils.acquireListKey(this.getCacheName(), key);
|
}
|
|
public void print(){
|
int size = 2;
|
if(this.listMap.size() > 10){
|
logger.info("内存中已经超过10条数据,总量 = " + this.listMap.size() + " 个集合,只打印前10条");
|
size = 10;
|
}
|
int count = 0;
|
for(Map.Entry<String, List> entry : this.listMap.entrySet()){
|
if(count > size){
|
break;
|
}
|
logger.info("key = {}, value = {}", entry.getKey(), entry.getValue());
|
count ++;
|
}
|
}
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
}
|