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