package com.jarvis.cache; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jarvis.cache.annotation.Cache; import com.jarvis.cache.aop.CacheAopProxyChain; import com.jarvis.cache.to.AutoLoadConfig; import com.jarvis.cache.to.AutoLoadTO; import com.jarvis.cache.to.CacheKeyTO; import com.jarvis.cache.to.CacheWrapper; /** * 用于处理自动加载缓存,sortThread 从autoLoadMap中取出数据,然后通知threads进行处理。 * @author jiayu.qiu */ public class AutoLoadHandler { private static final Logger logger=LoggerFactory.getLogger(AutoLoadHandler.class); public static final Integer AUTO_LOAD_MIN_EXPIRE=120; /** * 自动加载队列 */ private final ConcurrentHashMap<CacheKeyTO, AutoLoadTO> autoLoadMap; private final AbstractCacheManager cacheManager; /** * 缓存池 */ private final Thread threads[]; /** * 排序进行,对自动加载队列进行排序 */ private final Thread sortThread; /** * 自动加载队列 */ private final LinkedBlockingQueue<AutoLoadTO> autoLoadQueue; private volatile boolean running=false; /** * 自动加载配置 */ private final AutoLoadConfig config; /** * 随机数种子 */ private static final ThreadLocal<Random> random=new ThreadLocal<Random>() { @Override protected Random initialValue() { return new Random(); } }; /** * @param cacheManager 缓存的set,get方法实现类 * @param config 配置 */ public AutoLoadHandler(AbstractCacheManager cacheManager, AutoLoadConfig config) { this.cacheManager=cacheManager; this.config=config; if(this.config.getThreadCnt() > 0) { this.running=true; this.threads=new Thread[this.config.getThreadCnt()]; this.autoLoadMap=new ConcurrentHashMap<CacheKeyTO, AutoLoadTO>(this.config.getMaxElement()); this.autoLoadQueue=new LinkedBlockingQueue<AutoLoadTO>(this.config.getMaxElement()); this.sortThread=new Thread(new SortRunnable()); this.sortThread.setDaemon(true); this.sortThread.start(); for(int i=0; i < this.config.getThreadCnt(); i++) { this.threads[i]=new Thread(new AutoLoadRunnable()); this.threads[i].setName("autoLoadThread-" + i); this.threads[i].setDaemon(true); this.threads[i].start(); } } else { this.threads=null; this.autoLoadMap=null; this.autoLoadQueue=null; this.sortThread=null; } } public AutoLoadConfig getConfig() { return config; } public int getSize() { if(null != autoLoadMap) { return autoLoadMap.size(); } return -1; } public AutoLoadTO getAutoLoadTO(CacheKeyTO cacheKey) { if(null == autoLoadMap) { return null; } return autoLoadMap.get(cacheKey); } public void removeAutoLoadTO(CacheKeyTO cacheKey) { if(null == autoLoadMap) { return; } autoLoadMap.remove(cacheKey); } /** * 重置自动加载时间 * @param cacheKey 缓存Key */ public void resetAutoLoadLastLoadTime(CacheKeyTO cacheKey) { if(null == autoLoadMap) { return; } AutoLoadTO autoLoadTO=autoLoadMap.get(cacheKey); if(null != autoLoadTO && !autoLoadTO.isLoading()) { autoLoadTO.setLastLoadTime(1L); } } public void shutdown() { running=false; if(null != autoLoadMap) { autoLoadMap.clear(); } logger.info("----------------------AutoLoadHandler.shutdown--------------------"); } public AutoLoadTO putIfAbsent(CacheKeyTO cacheKey, CacheAopProxyChain joinPoint, Cache cache, CacheWrapper<Object> cacheWrapper) { if(null == autoLoadMap) { return null; } AutoLoadTO autoLoadTO=autoLoadMap.get(cacheKey); if(null != autoLoadTO) { return autoLoadTO; } try { if(!cacheManager.getScriptParser().isAutoload(cache, joinPoint.getArgs(), cacheWrapper.getCacheObject())) { return null; } } catch(Exception e) { logger.error(e.getMessage(), e); return null; } int expire=cacheWrapper.getExpire(); if(expire >= AUTO_LOAD_MIN_EXPIRE && autoLoadMap.size() <= this.config.getMaxElement()) { Object[] arguments=joinPoint.getArgs(); try { arguments=(Object[])cacheManager.getCloner().deepCloneMethodArgs(joinPoint.getMethod(), arguments); // 进行深度复制 } catch(Exception e) { logger.error(e.getMessage(), e); return null; } autoLoadTO=new AutoLoadTO(cacheKey, joinPoint, arguments, cache, expire); AutoLoadTO tmp=autoLoadMap.putIfAbsent(cacheKey, autoLoadTO); if(null == tmp) { return autoLoadTO; } else { return tmp; } } return null; } /** * 获取自动加载队列,如果是web应用,建议把自动加载队列中的数据都输出到页面中,并增加一些管理功能。 * @return autoload 队列 */ public AutoLoadTO[] getAutoLoadQueue() { if(null == autoLoadMap || autoLoadMap.isEmpty()) { return null; } AutoLoadTO tmpArr[]=new AutoLoadTO[autoLoadMap.size()]; tmpArr=autoLoadMap.values().toArray(tmpArr);// 复制引用 if(null != config.getSortType() && null != config.getSortType().getComparator()) { Arrays.sort(tmpArr, config.getSortType().getComparator()); } return tmpArr; } class SortRunnable implements Runnable { @Override public void run() { while(running) { int sleep=100; if(autoLoadMap.isEmpty() || autoLoadQueue.size() > 0) {// 如果没有数据 或 还有线程在处理,则继续等待 try { Thread.sleep(1000); } catch(InterruptedException e) { logger.error(e.getMessage(), e); } continue; } else if(autoLoadMap.size() <= threads.length * 10) { sleep=1000; } else if(autoLoadMap.size() <= threads.length * 50) { sleep=300; } try { Thread.sleep(sleep); } catch(InterruptedException e) { logger.error(e.getMessage(), e); } AutoLoadTO tmpArr[]=getAutoLoadQueue(); if(null == tmpArr || tmpArr.length == 0) { continue; } for(int i=0; i < tmpArr.length; i++) { try { AutoLoadTO to=tmpArr[i]; autoLoadQueue.put(to); if(i > 0 && i % 2000 == 0) { Thread.sleep(0);// 触发操作系统立刻重新进行一次CPU竞争, 让其它线程获得CPU控制权的权力。 } } catch(InterruptedException e) { logger.error(e.getMessage(), e); } catch(Exception e) { logger.error(e.getMessage(), e); } } } } } class AutoLoadRunnable implements Runnable { @Override public void run() { while(running) { try { AutoLoadTO tmpTO=autoLoadQueue.take(); if(null != tmpTO) { loadCache(tmpTO); Thread.sleep(config.getAutoLoadPeriod()); } } catch(InterruptedException e) { logger.error(e.getMessage(), e); } } } private void loadCache(AutoLoadTO autoLoadTO) { if(null == autoLoadTO) { return; } long now=System.currentTimeMillis(); if(autoLoadTO.getLastRequestTime() <= 0 || autoLoadTO.getLastLoadTime() <= 0) { return; } Cache cache=autoLoadTO.getCache(); long requestTimeout=cache.requestTimeout(); if(requestTimeout > 0 && (now - autoLoadTO.getLastRequestTime()) >= requestTimeout * 1000) {// 如果超过一定时间没有请求数据,则从队列中删除 autoLoadMap.remove(autoLoadTO.getCacheKey()); return; } if(autoLoadTO.getLoadCnt() > 100 && autoLoadTO.getAverageUseTime() < 10) {// 如果效率比较高的请求,就没必要使用自动加载了。 autoLoadMap.remove(autoLoadTO.getCacheKey()); return; } // 对于使用频率很低的数据,也可以考虑不用自动加载 long difFirstRequestTime=now - autoLoadTO.getFirstRequestTime(); long oneHourSecs=3600000L; if(difFirstRequestTime > oneHourSecs && autoLoadTO.getAverageUseTime() < 1000 && (autoLoadTO.getRequestTimes() / (difFirstRequestTime / oneHourSecs)) < 60) {// 使用率比较低的数据,没有必要使用自动加载。 autoLoadMap.remove(autoLoadTO.getCacheKey()); return; } if(autoLoadTO.isLoading()) { return; } int expire=autoLoadTO.getExpire(); if(expire < AUTO_LOAD_MIN_EXPIRE) {// 如果过期时间太小了,就不允许自动加载,避免加载过于频繁,影响系统稳定性 return; } // 计算超时时间 int alarmTime=autoLoadTO.getCache().alarmTime(); long timeout; if(alarmTime > 0 && alarmTime < expire) { timeout=expire - alarmTime; } else { if(expire >= 600) { timeout=expire - 120; } else { timeout=expire - 60; } } int rand=random.get().nextInt(10); timeout=(timeout + (rand % 2 == 0 ? rand : -rand)) * 1000; if((now - autoLoadTO.getLastLoadTime()) < timeout) { return; } CacheWrapper<Object> result=null; if(config.isCheckFromCacheBeforeLoad()) { try { Method method=autoLoadTO.getJoinPoint().getMethod(); // Type returnType=method.getGenericReturnType(); result=cacheManager.get(autoLoadTO.getCacheKey(), method, autoLoadTO.getArgs()); } catch(Exception ex) { } if(null != result) {// 如果已经被别的服务器更新了,则不需要再次更新 autoLoadTO.setExpire(result.getExpire()); if(result.getLastLoadTime() > autoLoadTO.getLastLoadTime() && (now - result.getLastLoadTime()) < timeout) { autoLoadTO.setLastLoadTime(result.getLastLoadTime()); return; } } } CacheAopProxyChain pjp=autoLoadTO.getJoinPoint(); CacheKeyTO cacheKey=autoLoadTO.getCacheKey(); DataLoaderFactory factory=DataLoaderFactory.getInstance(); DataLoader dataLoader=factory.getDataLoader(); CacheWrapper<Object> newCacheWrapper=null; try { newCacheWrapper=dataLoader.init(pjp, autoLoadTO, cacheKey, cache, cacheManager).loadData().getCacheWrapper(); } catch(Throwable e) { logger.error(e.getMessage(), e); } long loadDataUseTime=dataLoader.getLoadDataUseTime(); boolean isFirst=dataLoader.isFirst(); factory.returnObject(dataLoader); if(isFirst) { if(null == newCacheWrapper && null != result) {// 如果加载失败,则把旧数据进行续租 int newExpire=AUTO_LOAD_MIN_EXPIRE + 60; newCacheWrapper=new CacheWrapper<Object>(result.getCacheObject(), newExpire); } try { if(null != newCacheWrapper) { cacheManager.writeCache(pjp, autoLoadTO.getArgs(), cache, cacheKey, newCacheWrapper); autoLoadTO.setLastLoadTime(newCacheWrapper.getLastLoadTime())// 同步加载时间 .setExpire(newCacheWrapper.getExpire())// 同步过期时间 .addUseTotalTime(loadDataUseTime); } } catch(Exception e) { logger.error(e.getMessage(), e); } } } } }