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; /** *

抽象的内存缓存对象,以纯内存方式管理缓存的基类 * @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 cacheMap = new ConcurrentHashMap(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 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)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("该方法由RedisCache或者业务自定义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 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 getIterator(Class clazz) { throw new UnsupportedOperationException(); } public long getPersistentSize() { return 0; } @Override public long size(){ return cacheMap.size(); } /** * 返回给定限制的缓存数据集合 * @param maxSize 限制的最大数量 * @return */ @Override public Collection queryListLimit(int maxSize){ if(maxSize < 0 || maxSize >=Integer.MAX_VALUE){ return null; } if(cacheMap.size() <= maxSize){ ObjectMapper mapper = new ObjectMapper(); // 当缓存数量小于给定限制,显示全部 List 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 getKeys() { Set keyList = new HashSet<>(); for(Iterator it = this.cacheMap.keySet().iterator(); it.hasNext();){ keyList.add(it.next()); } return keyList; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~ 2023-06-13 操作集合,但目前没有使用,感觉删除整个集合还比较麻烦。 //~ 2023-06-14 确定使用该对象,并测试结果。 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private ConcurrentHashMap listMap = new ConcurrentHashMap<>(CacheConfig.INIT_CACHEMAP_SIZE); @Override public void putList(String key, List 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 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 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 entry : this.listMap.entrySet()){ if(count > size){ break; } logger.info("key = {}, value = {}", entry.getKey(), entry.getValue()); count ++; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ }