package com.walker.cache; import com.walker.db.page.GenericPager; import com.walker.infrastructure.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; /** * 抽象的缓存对象提供者。

* 每个应用缓存对象都需要实现一个此对象,如:用户缓存、参数缓存等。 * @author shikeying * * @param */ public abstract class AbstractCacheProvider implements CacheProvider, FactoryBean> { protected static Logger logger = LoggerFactory.getLogger(AbstractCacheProvider.class); protected Cache userCache = null; // 加载的缓存总记录数 protected AtomicLong count = new AtomicLong(0); // 是否支持分页加载(初始化缓存) private boolean loadPage = false; private int pageSize = 128; private long createTime = 0; private Map cacheParam = null; private boolean useRedis = false; public boolean isUseRedis() { return useRedis; } public void setUseRedis(boolean useRedis) { this.useRedis = useRedis; } @Override public Map getCacheParam() { return cacheParam; } public void setCacheParam(Map cacheParam) { this.cacheParam = cacheParam; } @Override public long getCreateTime() { return createTime; } @Override public void setPageSize(int pageSize) { this.pageSize = pageSize; } @Override public boolean isLoadPage() { return loadPage; } @Override public void setLoadPage(boolean loadPage) { this.loadPage = loadPage; } @Override public void afterPropertiesSet() throws Exception { if(getProviderType() == null) throw new AbstractMethodError("getProviderType() must be enforced!"); String name = getProviderName(); if(StringUtils.isEmpty(name)){ name = String.valueOf(System.currentTimeMillis()); } if(userCache != null){ // 2023-08-26 userCache = null; } // userCache = new RigidMemoryCache(name); // 这里修改,使用用户自定义的缓存对象实例 2016-11-17 userCache = provideCacheInstance(name, getCacheParam()); this.createTime = System.currentTimeMillis(); if(isUseRedis()){ // 2023-06-14 让具体子类实现去加载,因为可能存在持久化数据变动,因此让业务决定如何重新加载! // 如果是基于数据库的缓存,如:redis,并且库中已经存在数据,就不需要初始化进去 // long dbSize = this.size(); // if(dbSize > 0){ // logger.info("缓存'"+name+"'基于数据库缓存,而且已经存在数据,因此不再初始化加载"); // return; // } } if(this.loadPage){ // 分页加载数据 GenericPager firstPage = this.loadPageDataToCache(userCache, 1, pageSize); if(firstPage == null){ logger.info("...... 未加载到任何业务数据作为缓存,第一页空:" + this.getProviderName()); return; } count.set(firstPage.getTotalRows()); if(count.get() > 0){ int pageCount = firstPage.getPageCount(); logger.info("缓存 '" + this.getProviderName() + "' 数据分页 = " + pageCount); if(pageCount > 1){ // pageCount = 2 or 3/4/5... for(int i=2; i * 如果业务要使用自定义如:redis,请覆盖该方法。 * @param param * @return */ protected Cache provideCacheInstance(String name, Map param){ return new RigidMemoryCache(name); } /** * 由应用系统加载持久化数据到缓存对象中,如下: *
	 * List list = getResultFromDB();
	 * for(T data : list){
	 * 	cache.put(data.getId(), data);
	 * }
	 * 
* @param cache * @return */ protected abstract int loadDataToCache(Cache cache); /** * 分页加载数据到缓存中 * @param cache * @param pageIndex * @param pageSize * @return */ protected GenericPager loadPageDataToCache(Cache cache, int pageIndex, int pageSize){ return null; } @Override public void destroy() throws Exception { if(userCache != null){ // 这里不能在销毁时擦除数据,否则redis实现会直接删除磁盘缓存数据!2023-09-02 // userCache.clear(); } } @Override public Cache getCache() { if(userCache == null) throw new NullPointerException("not found cache: " + getProviderName()); return userCache; } @SuppressWarnings("unchecked") @Override public T getCacheData(String key) { assert (StringUtils.isNotEmpty(key)); return (T)userCache.get(key); } @Override public long getCacheCount(){ return count.get(); } @Override public void removeCacheData(String key) { userCache.remove(key); count.decrementAndGet(); if(count.get() < 0){ count.set(0); } } @Override public void updateCacheData(String key, T data) { assert (StringUtils.isNotEmpty(key)); assert (data != null); userCache.replace(key, data); } @Override public void putCacheData(String key, T data){ assert (StringUtils.isNotEmpty(key)); assert (data != null); userCache.put(key, data); count.incrementAndGet(); } @Override public void putCacheData(String key, T data, long expiredSeconds){ assert (StringUtils.isNotEmpty(key)); assert (data != null); assert(expiredSeconds > 0); userCache.put(key, data, expiredSeconds); // 带有时间期限的数据,不再记录累加数据量(这样无意义) } public String toString(){ return new StringBuilder().append("cacheName = ").append(getProviderName()) .append(", cache = ").append(userCache).toString(); } @Override public void reload() throws Exception{ // destroy(); if(userCache != null) { // 2023-09-04 重新加载时,原有缓存会被擦出,redis中的也会被删除! userCache.clear(); userCache = null; } afterPropertiesSet(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 修改时间:2014-11-24 // 作者:shikeying // 描述:把cacheProvider改成FactoryBean对象,这样就会优先比其他bean提早初始化。 // 以下为修改后,需要实现的方法 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public CacheProvider getObject() throws Exception { logger.debug("............通过CacheProviderFactoryBean获得缓存对象: " + this.getProviderName()); SimpleCacheManager.addCacheProvider(this); return this; } @Override public Class getObjectType() { return CacheProvider.class; } @Override public boolean isSingleton() { return true; } @Override public long size(){ return this.userCache.size(); } /** * 返回给定限制的缓存数据集合 * @param maxSize 限制的最大数量 * @return */ @Override public Collection queryListLimit(int maxSize){ return this.userCache.queryListLimit(maxSize); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~ 集合操作方法,是用集合就不能重复使用Map方式了!!! //~ 2023-06-13 操作集合,但目前没有使用,感觉删除整个集合还比较麻烦。 //~ 2023-06-14 确定使用该对象,并测试结果。 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void putCacheList(String key, List data){ this.putCacheList(key, data, 0); } @Override public void putCacheList(String key, List data, long expiredSeconds){ if(StringUtils.isEmptyList(data)){ throw new IllegalArgumentException("list is required!"); } if(StringUtils.isEmpty(key)){ throw new IllegalArgumentException("key is required!"); } this.userCache.putList(key, (List)data, expiredSeconds); } @Override public void putCacheListAppend(String key, T data){ this.checkKey(key, data); this.userCache.putListAppend(key, data); } @Override public List getCacheList(String key){ if(StringUtils.isEmpty(key)){ throw new IllegalArgumentException("key is required!"); } return (List)this.userCache.getList(key, 0, -1, getProviderType()); } @Override public void removeCacheList(String key, T data){ this.userCache.removeList(key, data); } @Override public void removeCacheList(String key){ this.userCache.removeList(key); } private void checkKey(String key, T data){ if(data == null){ throw new IllegalArgumentException("data is required!"); } if(StringUtils.isEmpty(key)){ throw new IllegalArgumentException("key is required!"); } } }